2026-08-14

SPF kaydı inceleme

SMTP protokolünün istenmeyen mesajlara karşı hiçbir savunmasının olmamasından dolayı SPF (sender policy framework) denen bir koruma mekanizması var. Her alan adı, yetkilendirdiği "eposta gönderebilen IP adreslerini" belirtmeli. Bunu yapmak üzere seçilen yöntem, DNS sunucuya bir TXT kaydı oluşturmak.

Bu kayıt

v=spf1

ile başlamalı. Bu, yürürlükteki SPF sürümünü gösteriyor; henüz sürüm 1.

İkinci olarak eposta göndermekle yetkili sunucumuzun IP adresi olmalı. Bunu IPv4 veya IPv6 öneki ile belirtebiliriz. Örneğin

ip4:144.178.36.0/24

veya

ip6:2a01:b747:3001:200::/56

gibi. Tek bir IP veya CIDR notasyonu ile bir subnet olabilir. Ama bu eposta gönderme işini Google veya Microsoft gibi bir firmanın sunduğu hizmetler ile yapıyorsak bu iş için onların SPF kaydını bizim kaydımıza dahil edebiliriz.

include:_spf.google.com 

Son aşamada da bizim yetkilendirdiğimiz IP adresleri veya dış hizmetlerin dışında gönderilmiş tüm eposta mesajlarına ne yapılması gerektiği ile ilgili önerimizi belirtebiliriz. Bu sadece öneri. Herkesin uyacağı kesin bir kural değil. Olası seçenekler şunlar

-all    # Fail: Geri kalan mesajların hepsi geçersizdir
~all    # Soft fail: Hepsi geçersiz olabilir, alıcı karar versin
?all    # Neutral: Bu konuda bir davranış belirlenmemiş
+all    # Pass: Hepsi geçerli olsun 

Bugün geçerli olan bir örnek vereyim. 57.103.88.43 adresinden gelen ve isim@icloud.com gibi bir gönderen adresine sahip mesaj acaba gerçekten Apple sunucularından mı gönderilmiştir? Önce icloud.com alan adına ait SPF kaydını sorgulayalım. Ben isim çözümlemeleri için CloudFlare'in 1.1.1.1 DNS sunucusunu kullandım ama belirtilmesi zorunlu değil, başka geçerli/güvenilir bir sunucu da kullanılabilir.

Resolve-DnsName -Name icloud.com -Type TXT -Server 1.1.1.1

Bu cmdlet şöyle bir çıktı üretti:

Name               Type   TTL   Section    Strings
----               ----   ---   -------    -------
icloud.com         TXT    3207  Answer     {google-site-verification=Ik3jMkCjHnUgyIo
                                           FR0Kw74srr0H5ynFmUk8fyY1uBck}
icloud.com         TXT    3207  Answer     {google-site-verification=knAEOH4QxR29I4g
                                           jRkpkvmUmP2AA7WrDk8Kq0wu9g9o}
icloud.com         TXT    3207  Answer     {yahoo-verification-key=Ga0ZBHHIemhhe2EkR
                                           77Byx+IKXuf2Ezi90h0e6draoQ=}
icloud.com         TXT    3207  Answer     {google-site-verification=Gc0Hl3EIrWDLXgi
                                           svPdkUCAEwNs0gg5JHtd2pZD3J04}
icloud.com         TXT    3207  Answer     {v=spf1 redirect=_spf.icloud.com}

Bir alan adının birden fazla TXT kaydı olabilir ama sadece bir tane SPF kaydı olabilir. Birden fazla SPF kaydı geçerli değil. Burada bizim ilgilendiğimiz en alttaki v=spf1 ile başlayan satır.

v=spf1 redirect=_spf.icloud.com

redirect de include gibi, ama kararı da tamamen yönlendirdiği alan adının kararına bırakıyor. include ile -all gibi bir seçim belirtmek mümkünken, redirect ile değil. Bu durumda Yapmamız gereken _spf.icloud.com için SPF kaydını bir daha sorgulamak.

Resolve-DnsName -Name _spf.icloud.com -Type TXT -Server 1.1.1.1

Bu da şöyle bir çıktı verdi:

v=spf1 include:_nets2.icloud.com include:_nets1.icloud.com include:_nets0.icloud.com ~all

Matruşka bebek gibi. Sıra

_nets0.icloud.com
_nets1.icloud.com
_nets2.icloud.com

URL'leri için SPF sogrusu yapmaya geldi. Sırasıyla bunları da yapınca aşağıdaki gibi bir sonuç elde ettim:

_nets0.icloud.com
    17.41.0.0/16
    17.58.0.0/16
    17.142.0.0/15
    17.57.155.0/24
    17.57.156.0/24

_nets1.icloud.com
    144.178.36.0/24
    144.178.38.0/24
    112.19.199.64/29
    112.19.242.64/29
    222.73.195.64/29
    157.255.1.64/29
    106.39.212.64/29
    123.126.78.64/29
    183.240.219.64/29
    39.156.163.64/29

_nets2.icloud.com
    57.103.64.0/18
    2a01:b747:3000:200::/56
    2a01:b747:3001:200::/56
    2a01:b747:3002:200::/56
    2a01:b747:3003:200::/56
    2a01:b747:3004:200::/56
    2a01:b747:3005:200::/56
    2a01:b747:3006:200::/56
    2a01:b747:3007::/56

Bana mesajı gönderen IP adresi 57.103.88.43 bu listede, _nets2 sorgusunun ilk satırında var. 57.103.64.0/18 subnet'inin sınırları:

57.103.64.1 - 57.103.127.254

arasında. Sonuç: gönderen IP adresi yetkilendirilmiş.

2026-08-13

Powershell, regex ve capture groups

Şöyle bir dosyam var, adı dosya.txt:

12.09.2014 Cihan  1993
01.10.2017 Zeynep 1992
02.05.2013 Mutlu  1991

Başlık satırı yok, virgülle ayrılmış değil, sabit uzunluklu.

Yeni öğrendiğim bir yöntem ile bu dosyayı okumak istedim:

gc dosya.txt | % {
    $a,$b,$c=$_ -split '(.{10}) (.{6}) (.{4})'
    [PSCustomObject]@{
        Tarih=$a
        Isim=$b
        Yil=$c
    }
}

Ama bu, beklediğim sonucu üretmedi. Burada

(.{10})    : 10 karakter uzunluğunda sabit genişlikli bir alan olarak tarih verisini, 

(.{6})    : 6 karakter uzunluğunda sabit genişlikli bir alan olarak isim verisini, 

(.{4})    : 4 karakter uzunluğunda sabit genişlikli bir alan olarak yil verisini

bulacak capture group'lar. Yukarıdaki ayrıştırıcı ile elde ettiğim sonuç aşağıdaki gibiydi:

Tarih Isim       Yil
----- ----       ---
      12.09.2014 {Cihan , 1993, }
      01.10.2017 {Zeynep, 1992, }
      02.05.2013 {Mutlu , 1991, }

Evet, tarih alanı boş ve tüm sütunlar kaymış. Hatta yıl sütunundan sonra virgülle ayrılmış bir boş alan daha var. Ben bunu şu şekilde çözmüştüm:

Get-Content veriler.txt | % {
    $a0,$a,$b,$c,$1=($_ -split '(.{10}) (.{6}) (.{4})')
    [PSCustomObject]@{
        Tarih=$a
        Isim=$b
        Yil=$c
    }
}

Yani burada $a0 ve $a1 değişkenlerini hiç hesaba dahil etmedim. Sonuç istediğim gibi oldu:

Tarih      Isim   Yil
-----      ----   ---
12.09.2014 Cihan  1993
01.10.2017 Zeynep 1992
02.05.2013 Mutlu  1991

Ama kod içime sinmedi. Neden gereksiz değişkenler kullanmak zorunda kaldım? Her bilişimcinin yapacağı gibi konuyu ayrıntılı olarak arama motorlarında aratmak yerine, Claude'a sordum. Cevabı şöyle:

Normal -split davranışı: Deseni bir "ayırıcı" (delimiter) olarak kullanır, ayırıcıyı bulur, ayırıcıyı atar ve geriye kalan parçaları döndürür.

Capture group'lu -split davranışı: Deseni yine ayırıcı olarak kullanır, ama bu sefer ayırıcıyı atmaz — parantez içindeki her bir capture group'un eşleştiği metni de sonuç dizisine ekler. Yani split hem "ayırıcının dışında kalan kısımları" hem de "ayırıcının içindeki (parantezlenmiş) kısımları" döndürür.

Bana çözüm önerileri olarak da şunları verdi:

1. Boş elemanları where-object ile süzmek

gc dosya.txt | % {
    $a,$b,$c=($_ -split '(.{10}) (.{6}) (.{4})') | Where-Object { $_ -ne "" }
    [PSCustomObject]@{
        Tarih=$a
        Isim=$b
        Yil=$c
    }
}

2. -split yerine -match kullanmak

gc dosya.txt | % {
    if ($_ -match '^(.{10}) (.{6}) (.{4})$') {
    [PSCustomObject]@{
        Tarih=$Matches[1]
        Isim=$Matches[2].Trim()
        Yil=$Matches[3]
    }
}


2026-08-12

Powershell, ilginç bir kullanım

Kirk Munro'nun şu videosunda anlattığı birşey çok ilginç geldi. Powershell'in böyle bir kullanımı olduğunu bilmiyordum. Zaten videonun da amacı bu; bilmediğimiz kullanımları göstermek.

Örnek bir metin dosyamız olsun, D:\dosya.txt gibi. Düz virgülle ayrılmış veri. Ama başlığı yok.

İstanbul,34,Marmara
Ankara,06,İç Anadolu
İzmir,34,Ege
Bursa,16,Marmara

Bu verileri, elbette

$veri = Import-CSV D:\dosya.txt -Header "Sehir","Plaka","Bolge"

gibi bir yolla okuyabiliriz. Ama ilginç bir yöntem olarak

$veri = gc D:\dosya.txt | % {$sehir, $plaka, $bolge = $_ -split ","; [PSCustomObject]@{Sehir=$sehir;Plaka=$plaka;Bolge=$bolge}}

gibi bir ifade ile de okuyabiliriz. Elbette, düz virgülle ayrılmış dosyanın okunması için ilk yöntem çok daha yerinde ama ikinci yöntemde 

$sehir, $plaka, $bolge = $_ -split ","

gibi bir atama ve buradan elde edilen verilerin yapılandırılmış olarak

$veri = ... [PSCustomObject]@{
    Sehir=$sehir
    Plaka=$plaka
    Bolge=$bolge
}

atanması bana çok şık geldi.

2026-08-11

Bilgisayarın bir dönemde ne kadar açık kaldığını bulmak

Örneğin son 30 günde bilgisayar ne kadar açık kalmış bulmak istiyorum. Microsoft tarafında bilgisayarın ne zaman açılıp ne zaman kapandığı konusu biraz karışık.

Eskiden sistem olay günlüğünde evenglog kaynağının 6005 ve 6006 olayları vardı, eventlog hizmetinin durup başlamasını kaydeden. Ama bu hizmetin durumunu takip etmek süper güvenilir bir yöntem değil.

İkinci yöntem Kernel-General kaynağının 12 ve 13 olayları olabilir. Bunlar daha güvenilir.

Ancak son dönemde hayatımıza giren fast boot (hızlı başlat) sonucunda, bilgisayar kapatılırken ne 6006 ne de 13 olay kaydının tutulmaması konuyu zor bir noktaya taşıdı. Bilgisayar artık kapanmıyor, bir çeşit uyku durumuna giriyor. Bunun sonucunda da Power-Troubleshooter kaynağından 1 olayını uyanma, Kernel-Power kaynağından 42 olayını da uykuya geçiş olarak düşünebiliriz.

Bitti mi? Hayır. Beklenmeyen bir kapanma olduğunda (elektrik kesintisi, mavi ekran vs) bilgisayar (elbette kapanırken bir kayıt düşmediği için) bir sonraki açılışta yaklaşık kapanmanın gerçekleştiği saate dair bir eventlog kaynağından 6008 olayı düşülüyor. Bununla birlikte Kernel-Power kaynağından 41 olayı da düşülüyor.

Özetle

açılma olayları:
    Power-Troubleshooter    1
    Eventlog                6005
    Kernel-General           12
 
kapanma olayları:
    Kernel-General        13
    Eventlog                6006
    Eventlog             6008
    Kernel-Power        107
    Kernel-Power        42

Ayıklamayı tamamladıktan sonra bu olayların arasındaki zaman farkını hesaplayarak toplamı bulmak lazım. Ama konu, özellikle 6008 olayı gibi sebeplerle biraz karışık.

2026-08-10

eventlog 6008 olayındaki beklenmedik karakter

Sistem olay günlüğünde eventlog kaynağından 6008 olayında şöyle bir kayıt düşülüyor:

"17:59:44, ‎24.‎07.‎2026 tarihinde gerçekleşen önceki sistem kapanışı beklenmiyordu."

Bu olay,  bilgisayarın "17:59:44, ‎24.‎07.‎2026" tarihinde beklenmedik bir şekilde kapanmasının ardından bilgisayar ilk kez açıldığında (kim bilir ne zaman) düşüldüğü için bu olayın TimeCreated alanı ile açıklama içinde geçen saat ve tarih bilgisinin birbiri ile hiç ilgisi yok.

Olayın açıklamasında geçen alanlara, şöyle erişebilirim:

$ev1 = Get-WinEvent -Filterhashtable @{Logname="System";ProviderName="eventlog";Id=6008} -Max 1
$tarih = $ev1.Properties[1].Value
$saat = $ev1.Properties[0].Value

ve bunu bir tarih nesnesine çevirmek için

Get-Date -Date "$saat $tarih"

gibi bir yöntem kullanabilirdim. Ama kullanamıyorum. Çünkü, tarih verisinin önünde yazılmayan özel bir karakter var, 0x200e. Nasıl bulunabilir:

"{0:X}" -f [int][char]$tarih[0]
200E 

Bu karakter, görüntülemenin soldan sağa yapılmasını sağlıyor. Zaten bir soldan sağa görüntülüyoruz. Ama sağdan sola yazılan bir dilde tarih verisinin ters olarak görüntülenmemesi için sanıyorum böyle bir düzenleme yapmışlar. Bu alandan kurtulmak lazım.

$tarih =  $ev1.Properties[1].Value -replace([char]0x200e,'')
Get-Date -Date "$saat $tarih"

yeterli.

2026-08-04

Windows bilgisayarlar için kimlik numarası (GDID)

Kullandığınız işletim sisteminin her hareketinizi takip edebildiği, sizi girdiğiniz her web sitesinde takip ettiğini bilseydiniz hala o işletim sistemini kullanabilir miydiniz?

Şu videoda söylenene göre her Windows bilgisayarın benzersiz bir kimlik numarası (GDID) var ve Microsoft, bir suçluyu bu kimlik numarasını takip ederek bulabildi. Bilgisayarınızın kimlik numarasının bir kopyası her ne kadar kayıt defterinde saklanıyor olsa da bunu silmemizin birşey değiştirmeyece söylenmiş. Ama neymiş diye merak ederseniz:

(gp "HKCU:\Software\Microsoft\IdentityCRL\ExtendedProperties").LID

Bunun benzeri bir durum Android için de olmuştu. Mahkemeye yansıyan bir anlaşmazlık, Google'ın konum bilgilerini adli makamlara vermesi sonucunda çözülebilmişti.

GDID konusunu Linus da işlemiş ve konuyu şöyle özetlemiş; GDID işletim sisteminin yeniden kurulması sonrasında aynı kalmıyor. Ancak çevrim içi bir hesap ile sisteme girip yapılması durumunda bütün gizem (!) çözülüyor.

2026-08-03

Linux'ta zaman

Bilgisayarlar kapalıyken bile tarih ve saat kaydını tutabilir. Bunu anakartın üzerinde bu işten sorumlu bir zamanlayıcı çip ile yaparlar. Linux dünyası bunu RTC (real time clock) olarak adlandırır. Bu yazıda zamanı tutulması ile bu çipte tutulan zaman bilgisinden bahsedilecektir.

Varsayılan olarak Linux zamanı UTC olarak tutar. Sistem yerelleştirmesi (daha doğrusu zaman dilimi ayarlaması) nasıl ayarlanmışsa bu zamanın üzerine eklenir veya çıkartılır. Örneğin Türkiye +3 zaman diliminde olduğu için UTC olarak tutulan zaman 3 saat ilave edilir.

Ama bunun istisnası da var. Linux'a zamanı yerel saat diliminde tut diyebiliyoruz. Öncelikle mevcut durumu kontrol edelim.

timedatectl

komutunun çıktıları arasında "RTC in local TZ" geçen satıra bakmalıyız. Bende bu

RTC in local TZ: yes

olduğu için benim sistemim demek ki saati yerel saat dilimine göre saklıyor. Bunu değiştirmek için timedatectl komutu ile birlikte set-local-rtc kullanabiliriz. Örneğin UTC zaman dilminde saklayan varsayılan kurulumda durumu yerel saat dilimine çevirmek için

timedatectl set-local-rtc true

diyebiilir, ya da tekrar UTC'ye çevirmek için

timedatectl set-local-rtc false

diyebiliriz. Ya da Windows'da saat bilgisini UTC olarak tutmak için aşağıdaki kayıt defteri değişikliği yapılabilir.

"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
          RealTimeIsUniversal = DWORD(1) 

Durum kontrolü için

(gp  "HKLM:\SYSTEM\CurrentControlSet\Control\TimeZoneInformation" "RealTimeIsUniversal").RealTimeIsUniversal

Zamanı yerel saat diliminde saklayan sistemimde

journalctl -b

komutu ile ilk kaydedilen olayın saatini incelediğimde garip bir şekilde mevcut saat dilimimde değil, bundan da 3 saat ötesinde bir saat görüyorum. Örneğin 13:19'da açtığım bilgisayarım için jounralctl'in ilk satırlarında 13:19 değil, 16:19 görüyorum. Bunun sebebi, ilk açılışta sistemi başlatan initramfs sisteminin sistemin RTC (real time clock) ile tutulan sistem zamanına +3 (Türkiye Saati) ilave ederek başlaması. Ancak bu bir yerde düzeliyor. İlk satırlar, kernel modülünün kayıtları:

Ağu 02 16:19:00 fedora3 kernel: Linux version 7.1.5-101.fc43.x86_64 (mockbuild@3a3dadcda8bc47f1a8cfdc1237822e70) (gcc (GCC) 15.3.1 202607>

Bir süre sonra initramfs işlevi sonlanıyor ve root filesystem'e geçiş yapılıyor. Bu noktadan sonra zaman hızlı bir şekilde 13:19'a  geçiş yapıyor.

Ağu 02 16:19:03 fedora3 systemd[1]: Starting initrd-switch-root.service - Switch Root...
Ağu 02 16:19:03 fedora3 systemd[1]: Switching root.
Ağu 02 16:19:03 fedora3 systemd-journald[260]: Journal stopped
Ağu 02 13:19:04 fedora3 systemd-journald[260]: Received SIGTERM from PID 1 (systemd).

last reboot komutu ile bakılınca görülen saat beklenen, yerel Türkiye saati 13:19:

last reboot -n 1
reboot   system boot  7.1.5-101.fc43.* Sun Aug  2 13:19   still running 

Windows tarafında benzer bir zaman değişikliği olmuyor, en azından yerel zaman dilimi olarak.