06 Nisan 2017

Kali Linux - Bölüm 14: Zamanlı İşler

Unix / Linux sistemlerde ilk zamanlarından bu yana gelişmiş bir özellik olan zamanlı işler özellikle sistem yöneticileri tarafından sıklıkla kullanılmaktadır. “cron” işleri örnek olarak düzenli olarak disk kullanım oranını ölçmek ve sistem yöneticisini uyarmak, uzun süredir kullanılmayan geçici dosyaları sistem üzerinden temizlemek gibi işlemlerde kullanılabilir. Ancak yapılan işlemlerin kritikliğine göre bu sistemi ve konfigürasyonunu iyi anlamak önemlidir.

Linux’da zamanlı işleri yöneten servis (ya da Unix terimiyle daemon) “cron” servisidir. Bildiğiniz gibi Kali Debian tabanlı bir dağıtım olup Debian da “systemd” init yöntemini kullanmaktadır. “systemd” unit’lerine baktığımızda “cron.service” unit’ini bunların arasında görebiliriz.


“cron” servisi sistem başlatıldığında process id’si “1” olan “init” prosesi (daha doğrusu systemd prosesi) tarafından başlatılır.


“cron” işlerini (cron jobs) tanımlayabileceğimiz birden fazla konfigürasyon dosyası var:
  • /etc/crontab: Sadece root kullanıcısı düzenleyebilir. Her bir işle ilgili kayıt için hangi kullanıcının hakları ile çalışacağı da kayıt içinde belirtilir.
  • /etc/cron.d: Bu dizinin altındaki dosyalar da sadece root kullanıcısı tarafından düzenlenebilir, /etc/crontab ile aynı formattadır ve aynı şekilde cron tarafından okunarak işletilirler.
  • /var/spool/cron/crontabs: Bu dizinin altında kullanıcıların tanımladığı crontab dosyaları yer alır. Bu dosyaların içindeki komutlar dosyanın sahibi olan kullanıcının hakları ile çalıştırılacağından kullanıcı adına ihtiyaç yoktur.
Bunlardan birincisini inceleyerek işe başlayalım.


“/etc/crontab” dosyasının erişim haklarına baktığımızda sadece “root” kullanıcınının yazma hakkı olduğunu görüyoruz.
“crontab” dosyasının içini incelediğimizde ise comment’lenmiş bölümde /etc/cron.d dizininin varlığını görüyoruz.


Bu dizin içinde de yine sadece “root” kullanıcısının yazabileceği dosyalar var ve bu dosyaların formatı da “/etc/crontab” ile aynı formatta.
Tekrar “/etc/crontab” dosyasını incelemeye dönelim. Comment’li bölümün hemen altında “SHELL” ve “PATH” değişkenlerinin tanımlandığını görüyoruz. Bunun nedeni cron işinin çalışmaya başlaması herhangi bir interaktif logon sonrası gerçekleşmediğinden bu çevresel değişkenlerin belirlenmemiş olması. Tabi çalıştıracağınız script’ler içinde de bu değişkenleri tanımlayabilirsiniz, ancak crontab dosyasında yaptığınız tanım tüm işler için geçerli olacaktır.
Bu bölümden sonra scheduling (planlama) işleminin yapıldığı, hangi komutun çalıştırılacağı ve bunun çıktısı ile ne yapılacağını tanımladığımız satırlar geliyor.
Planlama bölümünde sırasıyla aşağıdaki kriterleri girebilirsiniz:
  • m (minute / 0-59): Belirtilen saat(ler)in hangi dakikasında çalışacak
  • h (hour / 0-23): Belirtilen gün(ler)in hangi saatinde çalışacak
  • dom (day of month / 1-31): Belirtilen ay(lar)ın hangi günlerinde çalışacak
  • mon (month / 1-12 veya Jan-Dec): Hangi ay(lar)da çalışacak
  • dow (day of week / 0-7 [1:Pazartesi, 0 veya 7 Pazar]): Haftanın hangi gün(ler)inde çalışacak
Bu alanlarda “*” karakterinin bulunması “her” anlamına gelir. Bunun dışında virgül veya tire işaretiyle birden fazla değer de tanımlanabilir.
“/etc/crontab” dosyasındaki örneklere bir göz atalım:
Kali dağıtımı ile öntanımlı olarak gelen /etc/crontab dosyasının ilk schedule satırında şu bilgileri görüyoruz:


Bu satırda her saatin 17. dakikasında, “root” kullanıcısı olarak, “cd /” komutunun başarılı olması şartıyla (&& kendisinden önceki komutun başarılı olması şartıyla kendisinden sonraki komutun çalışmasını sağlayan operatördür), “run-parts” komutunun çalışmasına neden olacaktır. “run-parts” komutu kendisine parametre olarak verilen dizinin altındaki tüm çalıştırılabilir kodları ve script’leri çalıştırır.


Öntanımlı olarak bu dizinin altında herhangi bir script yok. Şimdi ikinci satıra göz atalım:


Bu satır her gün saat 06:25’de, yine “root” kullanıcı haklarıyla, “test –x usr/sbin/anacron” komutunun işletilmesini, bu komutun başarısız olması halinde ise kendinden sonra gelen “cd / && run-parts --report /etc/cron.daily” komutunun çalıştırılmasını sağlıyor.
“test” komutu kendisine parametre olarak verilen dosyanın var olup olmadığına ve “-x” opsiyonuyla kullanıldığında bu dosyanın çalıştırılabilir bir dosya olup olmadığına bakar. Eğer bu koşullar sağlanmazsa “false” yanıtı döndürür. Bizim sistemimizde bu dosya var mı kontrol edelim:


Bu dosya sistemimizde var olduğuna ve çalıştırılabilir olduğuna göre bu satır aslında hiçbir şey yapmayacaktır. Peki bu durumda saatlik işleri kim yapacak? Bunun cevabını vermeden önce saatlik işlerle ilgili (gelenek olarak, bunu sistematik olarak zorunlu kılan bir durum yok) scriptlerin bulunduğu /etc/cron.daily dizinine bakalım.


Bu dizinin içinde pek çok script var ve bunların başında da “0anacron” script’i geliyor. Bu dosyanın adının “0” ile başlaması tesadüf değil, (comment’li bölümde de açıklandığı gibi) diğer bütün script’lerden önce çalıştırılması istendiği için bu karakterle başlıyor adı.
Bu script ise önce “anacron” uygulamasının var ve çalıştırılabilir olmasını kontrol ediyor, ikinci satırsa ise “-u” opsiyonuyla sadece “cron.daily” işiyle çalıştırılan script’ler için zaman damgasını güncelliyor. Sözü geçen işin tanımlandığı ve “anacron” tarafından kullanılan konfigürasyon dosyası ise “/etc/anacron” dosyası:


Bu dosyanın formatı her ne kadar “/etc/crontab”a benzese de ondan farklı. Anacron’un cron dan en büyük farkı “dakika” ve “saat” bazında planlama yapılmasına imkan vermemesi, en küçük planlama zaman birimi “gün”den başlıyor. Yukarıda geçen cron.daily ifadesi bu dosyadaki satırla ilgili. Bu dosyanın formatını açıklamaya çalışırsak:
  • Period in days (kaç günde bir çalışacak)
  • Delay in minutes (sistem boot ettikten sonra kaç dakika beklemeli)
  • Job identifier (işin adı)
  • Command (işin kendisi)
Bu konfigürasyondan da anlaşılacağı üzere “anacron” saat konusuna pek önem vermiyor. “anacron”un “cron”un yanı sıra var olma nedeni sürekli çalışmayan sistemlerde (laptop, PC gibi) çalışacak ve sistem kapalıyken çalışamamış işleri (günlük işleri) daha fazla geciktirmeden boot edilir edilmez çalıştırmak. Peki “anacron”u kim çalıştıracak? Anacron, yine yukarıdaki konfigürasyon dosyasından anlaşılabileceği gibi sistem başlatıldığında çalışıyor, dolayısıyla init script’leri ile başlatılması gerek.


Yukarıdaki “systemctl status anacron” komutunun çıktısında en altta bulunan log bölümünde “anacron”un “systemd”, yani 1 numaralı ilk proses tarafından başlatıldığı görülmektedir. Ancak “anacron” ortalarda fazla görünmemiş ve işini bitirir bitirmez çıkış yapmıştır. “anacron” konusuna değinmeye devam edeceğiz. Evet oldukça karışık ama Linux’u anlamak ve bu sistemi bilinçli olarak kullanabilmek istiyorsak buna katlanmalıyız.
“/etc/crontab” dosyasındaki tanımlanmış komuta göre bu “/etc/cron.daily” dizinindeki scriptlerin “cron” tarafından çalıştırılmayacağını söylemiştik. Aynı durum haftalık ve aylık scriptlerin bulunduğu “/etc/weekly” ve “/etc/monthly” dizinleri için de geçerli. Ancak bu scriptlerin çalıştırıldığını biliyoruz. Nasıl olduğunu anlamak için şimdi “/etc/cron.d” dizinindeki cron tablolarına göz atalım.


Bu dizin altında 3 adet crontab dosyası var. “john” bir parola kırma aracı ve Kali’yi hazırlayanlar gece sistemin daha az kullanıldığı saatlerde parola kırmanın iyi bir fikir olduğunu düşünerek bu dosyayı eklemişler. Tabi içindeki satır comment’lenmiş, ancak ihtiyacınız varsa hazır bir şablon. Bu dizinde bizim için önemli olan dosya “anacron” dosyası. “/etc/cron.d” dizini altındaki dosyaların da aynen “/etc/crontab” gibi çalıştırıldığını ve aynı formatta olduğunu söylemiştik. Buna göre “anacron” crontab dosyası sayesinde her gün saat 07:30’da “anacron” çalıştırılabilir dosyasının varlığı test edildikten sonra “anacron” uygulaması başlatılıyor. “anacron” uygulaması da yukarıda açıklandığı üzere “/etc/anacrontab” dosyasını okuyarak cron.daily, cron.weekly ve cron.monthly işlerini çalıştırıyor.
“/etc/cron.daily/” dizininin altındaki dosyaları görmüştük. Şimdi “/etc/cron.weekly/” ve “/etc/cron.monthly/” dizinlerinin de altında ne olduğunu görelim.


Bunlarda da tıpkı “cron.daily” de olduğu gibi birer “0anacron” script’i var ve yine “cron.daily”de olduğu gibi bu script’ler de kendi periyodları için “/etc/anacrontab” dosyasında tanımlı işi script’lerin çalıştırılma zamanlarını güncellemek için kullanıyor. Peki ama bu zaman bilgileri nerede tutuluyor?


“anacron” gördüğünüz gibi iş bazında (çalıştırılan script’ler bazında değil) son çalıştığı zaman bilgisini gün bazında “/var/spool/anacron/” dizini altındaki dosyalara kaydediyor.
Biliyorum gereğinden fazla karmaşık, ama zamanlı işler tam olarak bu şekilde işliyor.
Son olarak kullanıcıların tanımladığı “cron” işlerine değinelim. Kullanıcıların tanımladıkları crontab dosyaları “/var/spool/cron/crontabs” dizini altındaki ilgili kullanıcının adıyla tanımlanmış dosyalardır.



Normal kullanıcıların “/var/spool/cron/crontab” dizinine erişimleri mümkün değil. Ancak “crontab –e” komutuyla tanımlayacakları crontab dosyası bu dizine yazılabilir. Bir başka alternatif de “crontab dosyaadı” komutu ile kullanıcının daha önce hazırladığı dosyanın crontab dosyası olarak yukarıdaki dizine yazılmasını sağlamaktır. “crontab” bu durumda format kontrolleri yapmakta ve bir format hatası varsa kullanıcıyı uyarmaktadır.
“crontab –l” komutu mevcut crontab dosyasını listeler. Örneğimizde henüz tanımlanmış bir crontab bulunmamaktadır. “crontab” ile ilk defa crontab dosyası tanımlamaya kalktığımızda bize hangi editör’ü tercih ettiğimizi soruyor. Öntanımlı seçenek olan “nano”yu seçtiğimizde bize şablon bir crontab dosyası sundu. Bu dosyanın “/etc/crontab” dosyasından tek farkı satırlarda kullanıcı adının bulunmaması, çünkü zaten her kullanıcının crontab dosyası farklı ve bu dosyadaki işler de bu kullanıcının hakları ile çalışacak.
Her kullanıcının crontab tanımlamamasını istiyorsak “/etc/cron.deny” veya “/etc/cron.allow” dosyaları ile bu izinleri ayarlayabiliriz.
Şimdi cron imkanını bir servisin erişilebilir olup olmadığını anlamak için kullanacağım. Bunun için “netcat” aracı ile bir sunucunun belli bir port’una port tarama modunda bağlantı kurmaya çalışacağım. Eğer netcat bağlantıyı kurabilirse “true” değerini döndürecek, kuramazsa da “false” değerini döndürecek.


“nc” komutunu kullanırken kullandığımız “-z” opsiyonu zero I/O anlamına geliyor ve bu opsiyon port tarama işlemlerinde kullanılıyor. Yani sadece karşıdaki servis ile bağlantı kurmaya çalışacağız, eğer başarılı olursak da bağlantıyı hemen sonlandıracağız. “-w” opsiyonu ise bağlantı zaman aşım süresini belirlemek için kullanılıyor.
Birinci adımda www.btrisk.com sunucusunun TCP 80 portuna bağlantı kurmak istiyorum. Port tarama modunda çalıştığım için bağlantı hemen sonlanıyor, ancak bağlantının başarılı olduğunu komutun döndürdüğü değeri “$?” shell parametre değerine bakarak görebiliyorum. Aynı işlemi TCP 8080 portu için yaptığımda ise sonuç farklı oluyor, geri döndürülen değer “0” dan farklı, yani “false”.
Bu farklılığı servisin erişilebilir olup olmadığını anlamak için kullanacağım.



“cron” servisi bu komutu her dakika çalıştırıyor. “cron” öntanımlı olarak eğer çalıştırdığı komutlar bir çıktı üretirse bunu crontab dosyasının sahibi olan kullanıcıya mail olarak atıyor. “crontab” tanımımızı yaptıktan bir süre sonra mail’imizi kontrol ettiğimizde herhangi bir mail gelmediğini görüyoruz. Yazdığımız komutu incelersek 2 komutu birbirlerinden “||” karakterleri ile ayırdığımızı görürsünüz. Bu karakterler sayesinde daha sonra gelen komut ancak önceki komut “false” değerini döndürürse çalışıyor. Şimdi bir de üzerinde herhangi bir servis çalışmayan TCP 8080 portunu deneyelim.



Yeni crontab dosyasını tanımladıktan yaklaşık 1-2 dk. sonra ilk mail’imizi alıyoruz. Türkçe karakterler hatalı çıkmış olsa da servise ulaşamadığımıza dair bilgilendirilmiş oluyoruz.
Pek çok serviste durum bu şekilde olmasına rağmen, “cron” daemon’ının (ya da servisinin) crontab dosyalarının değiştirilmesinden sonra yeniden başlatılmasına gerek yok. “cron” zaten her dakika başında crontab dosyalarının değişiklik zamanlarını kontrol ediyor ve eğer bir değişiklik olmuşsa yeni crontab dosyasını yüklüyor.
Önce mevcut crontab’ı “crontab –r” komutuyla silelim ve “cron” daemon’ının ürettiği syslog loglarından cron’un değişikliği yakaladığı yeri görelim.



Yukarıda görüldüğü gibi “cron” “btriskblog” kullanıcısının crontab’ının değiştiğini farkederek bu tabloyu yüklemiş. Tabi syslog dosyasını görebilmek için önce “root” kullanıcısı olmamız gerekti.

<<Önceki Bölüm                                                                                               Sonraki Bölüm>>