<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://sonsuzus.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://sonsuzus.github.io/" rel="alternate" type="text/html" /><updated>2026-07-22T07:13:24+00:00</updated><id>https://sonsuzus.github.io/feed.xml</id><title type="html">SonsuzUs</title><subtitle>Programlama ve Yazılım</subtitle><author><name>Sonsuz Us</name></author><entry><title type="html">ext4 Günlükleme Mekanizmasını dd ve hexdump ile Canlı İzlemek</title><link href="https://sonsuzus.github.io/posts/ext4-gunlukleme-mekanizmasini-dd-ve-hexdump-ile-canli-izlemek/" rel="alternate" type="text/html" title="ext4 Günlükleme Mekanizmasını dd ve hexdump ile Canlı İzlemek" /><published>2026-07-22T00:00:00+00:00</published><updated>2026-07-22T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/ext4-gunlukleme-mekanizmasini-dd-ve-hexdump-ile-canli-izlemek</id><content type="html" xml:base="https://sonsuzus.github.io/posts/ext4-gunlukleme-mekanizmasini-dd-ve-hexdump-ile-canli-izlemek/"><![CDATA[<p>ext4 dosya sisteminde bir dosya yazdığınızda verinin diske “hop diye” gitmediğini bilmek, Linux’un perde arkasını anlamak için harika bir başlangıçtır. Bu yazıda güvenli bir loop imaj üzerinde ext4 günlük bölgesini bulup, yazma işlemi sırasında <code class="language-plaintext highlighter-rouge">dd</code> ve <code class="language-plaintext highlighter-rouge">hexdump</code> ile anlık izleyen küçük bir Bash betiği hazırlayacağız. Gerçek diskinize dokunmadan, dosya sisteminin kalp atışlarını dinleyeceğiz.
``</p>

<p>ext4’ün günlükleme mekanizması, özellikle sistem çökmesi veya elektrik kesintisi gibi durumlarda dosya sisteminin tutarlı kalmasını sağlar. Basit fikir şudur: Kritik meta veri değişiklikleri önce “journal” denen özel bir alana yazılır, ardından asıl konumlarına uygulanır. Böylece sistem yarıda kesilirse ext4, günlüğe bakarak işlemi tamamlayabilir veya geri alabilir.</p>

<p>Teorik olarak bunu küçük bir işlem sırası gibi düşünebiliriz:</p>

\[T = \{metadata\ write, commit\ block, checkpoint\}\]

<p>Burada <code class="language-plaintext highlighter-rouge">commit block</code>, “bu işlem grubu tamamlandı” damgası gibidir. ext4 varsayılan olarak genellikle <code class="language-plaintext highlighter-rouge">data=ordered</code> kipinde çalışır: dosya verisi asıl yerine yazılır, meta veri ise journal üzerinden güvenceye alınır.</p>

<table>
  <thead>
    <tr>
      <th>Kip</th>
      <th style="text-align: right">Veri journal’a yazılır mı?</th>
      <th style="text-align: right">Meta veri journal’a yazılır mı?</th>
      <th style="text-align: right">Performans</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">data=journal</code></td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">Daha yavaş, daha güvenli</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">data=ordered</code></td>
      <td style="text-align: right">Hayır, önce diske gider</td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">Dengeli</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">data=writeback</code></td>
      <td style="text-align: right">Hayır</td>
      <td style="text-align: right">Evet</td>
      <td style="text-align: right">Hızlı, sıralama garantisi zayıf</td>
    </tr>
  </tbody>
</table>

<p>Journal alanı ext4 içinde çoğunlukla özel bir inode olarak tutulur: inode <code class="language-plaintext highlighter-rouge">8</code>. Biz bu inode’un fiziksel bloklarını <code class="language-plaintext highlighter-rouge">debugfs</code> ile bulacağız. Bir blok numarası $P$, blok boyutu $B$ ise byte cinsinden konum:</p>

\[offset = P \times B\]

<p><code class="language-plaintext highlighter-rouge">dd</code> komutu bu ofsete gidip blokları okuyacak, <code class="language-plaintext highlighter-rouge">hexdump</code> da bize ham içeriği gösterecek.</p>

<p>Önce güvenli bir laboratuvar oluşturalım:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">truncate</span> <span class="nt">-s</span> 256M ext4-lab.img
mkfs.ext4 <span class="nt">-F</span> ext4-lab.img
<span class="nb">mkdir</span> <span class="nt">-p</span> mnt-lab
<span class="nb">sudo </span>mount <span class="nt">-o</span> loop ext4-lab.img mnt-lab
</code></pre></div></div>

<p>Şimdi izleme betiğimiz gelsin. Bu betik imaj dosyasından blok boyutunu öğrenir, journal inode’unun ilk extent’ini bulur ve belirli aralıklarla o bölgeden veri okuyup hexadecimal biçimde gösterir.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>
<span class="nb">set</span> <span class="nt">-euo</span> pipefail

<span class="nv">IMG</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">1</span><span class="k">:-</span><span class="nv">ext4</span><span class="p">-lab.img</span><span class="k">}</span><span class="s2">"</span>
<span class="nv">BLOCKS_TO_READ</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">2</span><span class="k">:-</span><span class="nv">4</span><span class="k">}</span><span class="s2">"</span>
<span class="nv">INTERVAL</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">3</span><span class="k">:-</span><span class="nv">1</span><span class="k">}</span><span class="s2">"</span>

<span class="k">if</span> <span class="o">[[</span> <span class="o">!</span> <span class="nt">-f</span> <span class="s2">"</span><span class="nv">$IMG</span><span class="s2">"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
  </span><span class="nb">echo</span> <span class="s2">"İmaj bulunamadı: </span><span class="nv">$IMG</span><span class="s2">"</span> <span class="o">&gt;</span>&amp;2
  <span class="nb">exit </span>1
<span class="k">fi

</span><span class="nv">BS</span><span class="o">=</span><span class="si">$(</span>dumpe2fs <span class="nt">-h</span> <span class="s2">"</span><span class="nv">$IMG</span><span class="s2">"</span> 2&gt;/dev/null | <span class="nb">awk</span> <span class="nt">-F</span>: <span class="s1">'/Block size/ {gsub(/ /,"",$2); print $2}'</span><span class="si">)</span>

<span class="nv">JOURNAL_RANGE</span><span class="o">=</span><span class="si">$(</span>debugfs <span class="nt">-R</span> <span class="s1">'stat &lt;8&gt;'</span> <span class="s2">"</span><span class="nv">$IMG</span><span class="s2">"</span> 2&gt;/dev/null <span class="se">\</span>
  | <span class="nb">awk</span> <span class="s1">'
    match($0, /\):([0-9]+)-([0-9]+)/, a) { print a[1], a[2]; exit }
    match($0, /\):([0-9]+)/, a) { print a[1], a[1]; exit }
  '</span><span class="si">)</span>

<span class="nv">START_BLOCK</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$JOURNAL_RANGE</span><span class="s2">"</span> | <span class="nb">awk</span> <span class="s1">'{print $1}'</span><span class="si">)</span>
<span class="nv">END_BLOCK</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$JOURNAL_RANGE</span><span class="s2">"</span> | <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="si">)</span>

<span class="k">if</span> <span class="o">[[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="k">${</span><span class="nv">START_BLOCK</span><span class="k">:-}</span><span class="s2">"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
  </span><span class="nb">echo</span> <span class="s2">"Journal blokları bulunamadı. debugfs çıktısını kontrol edin."</span> <span class="o">&gt;</span>&amp;2
  <span class="nb">exit </span>1
<span class="k">fi

</span><span class="nv">OFFSET</span><span class="o">=</span><span class="k">$((</span>START_BLOCK <span class="o">*</span> BS<span class="k">))</span>

<span class="nb">printf</span> <span class="s2">"Blok boyutu      : %s byte</span><span class="se">\n</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$BS</span><span class="s2">"</span>
<span class="nb">printf</span> <span class="s2">"Journal başlangıcı: blok %s</span><span class="se">\n</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$START_BLOCK</span><span class="s2">"</span>
<span class="nb">printf</span> <span class="s2">"Journal bitişi    : blok %s</span><span class="se">\n</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$END_BLOCK</span><span class="s2">"</span>
<span class="nb">printf</span> <span class="s2">"Okunan offset     : %s byte</span><span class="se">\n\n</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$OFFSET</span><span class="s2">"</span>

<span class="k">while </span><span class="nb">true</span><span class="p">;</span> <span class="k">do
  </span>clear
  <span class="nb">date
  echo</span> <span class="s2">"Journal bölgesinden </span><span class="nv">$BLOCKS_TO_READ</span><span class="s2"> blok okunuyor..."</span>
  <span class="nb">dd </span><span class="k">if</span><span class="o">=</span><span class="s2">"</span><span class="nv">$IMG</span><span class="s2">"</span> <span class="nv">bs</span><span class="o">=</span><span class="s2">"</span><span class="nv">$BS</span><span class="s2">"</span> <span class="nv">skip</span><span class="o">=</span><span class="s2">"</span><span class="nv">$START_BLOCK</span><span class="s2">"</span> <span class="nv">count</span><span class="o">=</span><span class="s2">"</span><span class="nv">$BLOCKS_TO_READ</span><span class="s2">"</span> <span class="nv">status</span><span class="o">=</span>none <span class="se">\</span>
    | hexdump <span class="nt">-C</span> | <span class="nb">head</span> <span class="nt">-n</span> 40
  <span class="nb">sleep</span> <span class="s2">"</span><span class="nv">$INTERVAL</span><span class="s2">"</span>
<span class="k">done</span>
</code></pre></div></div>

<p>Kaydedip çalıştırın:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">chmod</span> +x watch-ext4-journal.sh
./watch-ext4-journal.sh ext4-lab.img 8 1
</code></pre></div></div>

<p>Başka bir terminalde dosya sistemine yazma yapalım:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for </span>i <span class="k">in</span> <span class="o">{</span>1..20<span class="o">}</span><span class="p">;</span> <span class="k">do
  </span><span class="nb">sudo dd </span><span class="k">if</span><span class="o">=</span>/dev/urandom <span class="nv">of</span><span class="o">=</span>mnt-lab/file-<span class="nv">$i</span>.bin <span class="nv">bs</span><span class="o">=</span>1M <span class="nv">count</span><span class="o">=</span>2 <span class="nv">status</span><span class="o">=</span>none
  <span class="nb">sync
  sleep </span>1
<span class="k">done</span>
</code></pre></div></div>

<p>İzleme ekranında bazı byte dizilerinin değiştiğini göreceksiniz. Bunlar her zaman “dosya içeriği” değildir; çoğunlukla inode, dizin girdisi, blok bitmap’i gibi meta veri değişikliklerinin journal kayıtlarıdır.</p>

<table>
  <thead>
    <tr>
      <th>Araç</th>
      <th>Görevi</th>
      <th>Neden kullanıyoruz?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">dumpe2fs</code></td>
      <td>ext4 süper blok bilgisini okur</td>
      <td>Blok boyutunu öğrenmek için</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">debugfs</code></td>
      <td>ext dosya sistemini inceler</td>
      <td>Journal inode’unun bloklarını bulmak için</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">dd</code></td>
      <td>Ham blok okur/yazar</td>
      <td>Journal bölgesini doğrudan okumak için</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">hexdump</code></td>
      <td>Byte’ları okunabilir gösterir</td>
      <td>Değişimleri gözlemlemek için</td>
    </tr>
  </tbody>
</table>

<p>Buradaki önemli nokta şudur: ext4 journal’ı bir metin günlüğü değildir; insanlar için değil, dosya sisteminin kendisi için tasarlanmış ikili bir yapıdır. Yani ekranda anlamlı cümleler değil, işlem kayıtlarının ham temsillerini görürsünüz. Yine de yazma yaptıkça bu alanın değiştiğini izlemek, journal fikrini soyut bir kavram olmaktan çıkarır.</p>

<p>Deney bitince temizleyin:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>umount mnt-lab
<span class="nb">rmdir </span>mnt-lab
<span class="nb">rm </span>ext4-lab.img
</code></pre></div></div>

<p>Bu küçük proje sayesinde ext4’ün “önce not al, sonra uygula” mantığını canlı gözlemledik. Dosya sistemleri sessiz çalışır; ama doğru araçlarla bakınca oldukça konuşkandırlar.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="ext4" /><category term="linux" /><category term="dd" /><category term="hexdump" /><category term="dosya-sistemi" /><summary type="html"><![CDATA[ext4 dosya sisteminde bir dosya yazdığınızda verinin diske “hop diye” gitmediğini bilmek, Linux’un perde arkasını anlamak için harika bir başlangıçtır. Bu yazıda güvenli bir loop imaj üzerinde ext4 günlük bölgesini bulup, yazma işlemi sırasında dd ve hexdump ile anlık izleyen küçük bir Bash betiği hazırlayacağız. Gerçek diskinize dokunmadan, dosya sisteminin kalp atışlarını dinleyeceğiz.]]></summary></entry><entry><title type="html">GDB Python ile Yığındaki Stringleri Avlayan Renkli Komut Yazmak</title><link href="https://sonsuzus.github.io/posts/gdb-python-ile-yigindaki-stringleri-avlayan-renkli-komut-yazmak/" rel="alternate" type="text/html" title="GDB Python ile Yığındaki Stringleri Avlayan Renkli Komut Yazmak" /><published>2026-07-22T00:00:00+00:00</published><updated>2026-07-22T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/gdb-python-ile-yigindaki-stringleri-avlayan-renkli-komut-yazmak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/gdb-python-ile-yigindaki-stringleri-avlayan-renkli-komut-yazmak/"><![CDATA[<p>Debug oturumunda bazen en değerli ipucu, register’larda değil yığının arasında saklanan minicik bir stringdir: bir token, hata mesajı, dosya yolu ya da “buradayım!” diye bağıran bir parola. GNU Debugger, Python API’si sayesinde yalnızca komut çalıştırdığımız bir araç olmaktan çıkar; kendi mini dedektif komutlarımızı yazabileceğimiz genişletilebilir bir platforma dönüşür.
``
Bu yazıda GDB’ye özel bir komut ekleyerek çalışan programın <strong>stack/yığın</strong> bellek bölgesini tarayacak, yazdırılabilir karakterlerden oluşan stringleri bulacak ve terminalde renklendirerek göstereceğiz. Ama önce sahneyi kuralım: yığın, fonksiyon çağrıları sırasında yerel değişkenlerin, dönüş adreslerinin ve geçici verilerin tutulduğu bellek alanıdır. Çoğu mimaride yığın aşağı doğru büyür; yani yeni veri eklendikçe adresler küçülür. Basitçe düşünürsek bir tarama aralığı için \(N = end - start\) bayt okuruz ve ardışık yazdırılabilir karakterleri string adayı kabul ederiz.</p>

<table>
  <thead>
    <tr>
      <th>Bölge</th>
      <th>Tipik İçerik</th>
      <th>Debug İçin Değeri</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Stack</td>
      <td>Yerel değişkenler, geçici buffer’lar</td>
      <td>Anlık durum ve sızıntı ipuçları</td>
    </tr>
    <tr>
      <td>Heap</td>
      <td>Dinamik ayrılan nesneler</td>
      <td>Uzun yaşayan veri yapıları</td>
    </tr>
    <tr>
      <td>.rodata</td>
      <td>Sabit stringler</td>
      <td>Programın gömülü mesajları</td>
    </tr>
  </tbody>
</table>

<p>GDB’nin Python tarafında en sevdiğimiz oyuncular <code class="language-plaintext highlighter-rouge">gdb.Command</code>, <code class="language-plaintext highlighter-rouge">gdb.selected_inferior()</code> ve <code class="language-plaintext highlighter-rouge">read_memory()</code> fonksiyonlarıdır. <code class="language-plaintext highlighter-rouge">gdb.Command</code> ile yeni komut tanımlarız, inferior dediğimiz şey debug edilen süreçtir, <code class="language-plaintext highlighter-rouge">read_memory()</code> ise belirli adres aralığındaki ham baytları okumamızı sağlar. Linux üzerinde <code class="language-plaintext highlighter-rouge">/proc/&lt;pid&gt;/maps</code> dosyasından <code class="language-plaintext highlighter-rouge">[stack]</code> satırını okuyarak gerçek yığın sınırlarını yakalayabiliriz.</p>

<p>Aşağıdaki betik <code class="language-plaintext highlighter-rouge">stackstrings</code> adlı yeni bir GDB komutu ekler. Minimum uzunluğu parametre olarak verebilir, aksi halde 4 karakterden uzun stringleri listeler. Çıktıda adresler mavi, stringler yeşil renktedir; çünkü debug yaparken biraz neon ışık herkesin hakkı!</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># stackstrings.py
</span><span class="kn">import</span> <span class="n">gdb</span>
<span class="kn">import</span> <span class="n">string</span>

<span class="n">GREEN</span> <span class="o">=</span> <span class="sh">'</span><span class="se">\033</span><span class="s">[92m</span><span class="sh">'</span>
<span class="n">BLUE</span> <span class="o">=</span> <span class="sh">'</span><span class="se">\033</span><span class="s">[94m</span><span class="sh">'</span>
<span class="n">YELLOW</span> <span class="o">=</span> <span class="sh">'</span><span class="se">\033</span><span class="s">[93m</span><span class="sh">'</span>
<span class="n">RESET</span> <span class="o">=</span> <span class="sh">'</span><span class="se">\033</span><span class="s">[0m</span><span class="sh">'</span>

<span class="n">PRINTABLE</span> <span class="o">=</span> <span class="nf">set</span><span class="p">(</span><span class="nf">bytes</span><span class="p">(</span><span class="n">string</span><span class="p">.</span><span class="n">printable</span><span class="p">,</span> <span class="sh">'</span><span class="s">ascii</span><span class="sh">'</span><span class="p">))</span> <span class="o">-</span> <span class="p">{</span><span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">}</span>

<span class="k">class</span> <span class="nc">StackStrings</span><span class="p">(</span><span class="n">gdb</span><span class="p">.</span><span class="n">Command</span><span class="p">):</span>
    <span class="sh">'''</span><span class="s">Yığın bölgesindeki yazdırılabilir stringleri bulur: stackstrings [min_len]</span><span class="sh">'''</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="nf">super</span><span class="p">(</span><span class="n">StackStrings</span><span class="p">,</span> <span class="n">self</span><span class="p">).</span><span class="nf">__init__</span><span class="p">(</span><span class="sh">'</span><span class="s">stackstrings</span><span class="sh">'</span><span class="p">,</span> <span class="n">gdb</span><span class="p">.</span><span class="n">COMMAND_DATA</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">get_stack_range</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="n">inferior</span> <span class="o">=</span> <span class="n">gdb</span><span class="p">.</span><span class="nf">selected_inferior</span><span class="p">()</span>
        <span class="n">pid</span> <span class="o">=</span> <span class="n">inferior</span><span class="p">.</span><span class="n">pid</span>
        <span class="k">if</span> <span class="n">pid</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">raise</span> <span class="n">gdb</span><span class="p">.</span><span class="nc">GdbError</span><span class="p">(</span><span class="sh">'</span><span class="s">Çalışan bir süreç yok. Önce run veya attach kullan.</span><span class="sh">'</span><span class="p">)</span>

        <span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="s">/proc/</span><span class="si">{</span><span class="n">pid</span><span class="si">}</span><span class="s">/maps</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">r</span><span class="sh">'</span><span class="p">)</span> <span class="k">as</span> <span class="n">maps</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">maps</span><span class="p">:</span>
                <span class="k">if</span> <span class="sh">'</span><span class="s">[stack]</span><span class="sh">'</span> <span class="ow">in</span> <span class="n">line</span><span class="p">:</span>
                    <span class="n">region</span> <span class="o">=</span> <span class="n">line</span><span class="p">.</span><span class="nf">split</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
                    <span class="n">start_s</span><span class="p">,</span> <span class="n">end_s</span> <span class="o">=</span> <span class="n">region</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="sh">'</span><span class="s">-</span><span class="sh">'</span><span class="p">)</span>
                    <span class="k">return</span> <span class="nf">int</span><span class="p">(</span><span class="n">start_s</span><span class="p">,</span> <span class="mi">16</span><span class="p">),</span> <span class="nf">int</span><span class="p">(</span><span class="n">end_s</span><span class="p">,</span> <span class="mi">16</span><span class="p">)</span>
        <span class="k">raise</span> <span class="n">gdb</span><span class="p">.</span><span class="nc">GdbError</span><span class="p">(</span><span class="sh">'</span><span class="s">Stack bölgesi bulunamadı.</span><span class="sh">'</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">invoke</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">arg</span><span class="p">,</span> <span class="n">from_tty</span><span class="p">):</span>
        <span class="n">min_len</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span> <span class="k">if</span> <span class="n">arg</span><span class="p">.</span><span class="nf">strip</span><span class="p">()</span> <span class="k">else</span> <span class="mi">4</span>
        <span class="n">start</span><span class="p">,</span> <span class="n">end</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">get_stack_range</span><span class="p">()</span>
        <span class="n">inferior</span> <span class="o">=</span> <span class="n">gdb</span><span class="p">.</span><span class="nf">selected_inferior</span><span class="p">()</span>
        <span class="n">mem</span> <span class="o">=</span> <span class="n">inferior</span><span class="p">.</span><span class="nf">read_memory</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="p">).</span><span class="nf">tobytes</span><span class="p">()</span>

        <span class="n">found</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">while</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="nf">len</span><span class="p">(</span><span class="n">mem</span><span class="p">):</span>
            <span class="k">if</span> <span class="n">mem</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="ow">in</span> <span class="n">PRINTABLE</span><span class="p">:</span>
                <span class="n">j</span> <span class="o">=</span> <span class="n">i</span>
                <span class="k">while</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="nf">len</span><span class="p">(</span><span class="n">mem</span><span class="p">)</span> <span class="ow">and</span> <span class="n">mem</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="ow">in</span> <span class="n">PRINTABLE</span><span class="p">:</span>
                    <span class="n">j</span> <span class="o">+=</span> <span class="mi">1</span>
                <span class="k">if</span> <span class="n">j</span> <span class="o">-</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="n">min_len</span><span class="p">:</span>
                    <span class="n">raw</span> <span class="o">=</span> <span class="n">mem</span><span class="p">[</span><span class="n">i</span><span class="p">:</span><span class="n">j</span><span class="p">]</span>
                    <span class="n">text</span> <span class="o">=</span> <span class="n">raw</span><span class="p">.</span><span class="nf">decode</span><span class="p">(</span><span class="sh">'</span><span class="s">ascii</span><span class="sh">'</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="sh">'</span><span class="s">replace</span><span class="sh">'</span><span class="p">)</span>
                    <span class="n">addr</span> <span class="o">=</span> <span class="n">start</span> <span class="o">+</span> <span class="n">i</span>
                    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">BLUE</span><span class="si">}</span><span class="s">0x</span><span class="si">{</span><span class="n">addr</span><span class="si">:</span><span class="n">x</span><span class="si">}{</span><span class="n">RESET</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">GREEN</span><span class="si">}{</span><span class="n">text</span><span class="si">}{</span><span class="n">RESET</span><span class="si">}</span><span class="sh">'</span><span class="p">)</span>
                    <span class="n">found</span> <span class="o">+=</span> <span class="mi">1</span>
                <span class="n">i</span> <span class="o">=</span> <span class="n">j</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span>

        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">YELLOW</span><span class="si">}</span><span class="s">Toplam </span><span class="si">{</span><span class="n">found</span><span class="si">}</span><span class="s"> string bulundu. Aralık: 0x</span><span class="si">{</span><span class="n">start</span><span class="si">:</span><span class="n">x</span><span class="si">}</span><span class="s">-0x</span><span class="si">{</span><span class="n">end</span><span class="si">:</span><span class="n">x</span><span class="si">}{</span><span class="n">RESET</span><span class="si">}</span><span class="sh">'</span><span class="p">)</span>

<span class="nc">StackStrings</span><span class="p">()</span>
</code></pre></div></div>

<p>Kullanmak için betiği kaydedip GDB içinde yüklemek yeterli:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gdb ./program
<span class="o">(</span>gdb<span class="o">)</span> run
<span class="o">(</span>gdb<span class="o">)</span> <span class="nb">source </span>stackstrings.py
<span class="o">(</span>gdb<span class="o">)</span> stackstrings 6
</code></pre></div></div>

<p>Buradaki algoritma oldukça basittir: belleği soldan sağa tarar, karakter <code class="language-plaintext highlighter-rouge">PRINTABLE</code> kümesindeyse bir koşu başlatır, koşu uzunluğu minimum değeri geçerse sonuç üretir. Zaman karmaşıklığı \(O(N)\), bellek maliyeti ise okunan yığın kadar yani \(O(N)\) kabul edilir. Büyük yığınlarda parça parça okuma yapılabilir; fakat öğretici olması için tek parça okuma daha anlaşılırdır.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">/proc/pid/maps</code> ile sınır bulma</td>
      <td>Gerçek stack aralığını tarar</td>
      <td>Linux odaklıdır</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">$sp</code> çevresini tarama</td>
      <td>Taşınabilir fikre daha yakındır</td>
      <td>Tüm yığını kaçırabilir</td>
    </tr>
    <tr>
      <td>Sabit adres aralığı</td>
      <td>Hızlı test edilir</td>
      <td>ASLR nedeniyle kırılgandır</td>
    </tr>
  </tbody>
</table>

<p>Bu komut özellikle CTF, tersine mühendislik, exploit geliştirme ve “ben bu değişkene ne zaman ne yazdım?” soruşturmasında işe yarar. Yine de dikkat: Stack içinde gördüğünüz her karakter dizisi anlamlı string değildir. Rastgele baytlar bazen tesadüfen okunabilir karakterlere dönüşebilir. Bu yüzden bulunan sonuçları bağlamla, register’larla ve backtrace ile birlikte değerlendirmek gerekir.</p>

<p>Sonuç olarak GDB’nin Python API’si, debugger’ı kişisel bir analiz laboratuvarına çevirir. Bugün stack stringlerini renklendirdik; yarın heap tarayıcı, otomatik breakpoint raporlayıcı ya da şüpheli pointer avcısı yazabilirsiniz. Debug dünyasında büyüteç sizde, Python ise büyütecin LED ışığıdır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="gdb" /><category term="python" /><category term="debugging" /><category term="stack" /><category term="reverse-engineering" /><summary type="html"><![CDATA[Debug oturumunda bazen en değerli ipucu, register’larda değil yığının arasında saklanan minicik bir stringdir: bir token, hata mesajı, dosya yolu ya da “buradayım!” diye bağıran bir parola. GNU Debugger, Python API’si sayesinde yalnızca komut çalıştırdığımız bir araç olmaktan çıkar; kendi mini dedektif komutlarımızı yazabileceğimiz genişletilebilir bir platforma dönüşür.]]></summary></entry><entry><title type="html">Linux ile Kötü Ağ Simülatörü: Sanal Arayüzde %5 Paket Kaybı ve Rastgele Gecikme</title><link href="https://sonsuzus.github.io/posts/linux-ile-kotu-ag-simulatoru-sanal-arayuzde-5-paket-kaybi-ve-rastgele-gecikme/" rel="alternate" type="text/html" title="Linux ile Kötü Ağ Simülatörü: Sanal Arayüzde %5 Paket Kaybı ve Rastgele Gecikme" /><published>2026-07-22T00:00:00+00:00</published><updated>2026-07-22T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/linux-ile-kotu-ag-simulatoru-sanal-arayuzde-5-paket-kaybi-ve-rastgele-gecikme</id><content type="html" xml:base="https://sonsuzus.github.io/posts/linux-ile-kotu-ag-simulatoru-sanal-arayuzde-5-paket-kaybi-ve-rastgele-gecikme/"><![CDATA[<p>Uygulamanız lokal makinede ışık hızında çalışıyor olabilir; peki kullanıcı metroda, otel Wi‑Fi’ında ya da yağmurlu bir günde 4G’deyken ne olacak? Bu yazıda Linux üzerinde sanal bir ağ arayüzü oluşturup gelen paketlere yapay olarak %5 paket kaybı ve rastgele gecikme ekleyen küçük ama çok faydalı bir “kötü ağ simülatörü” kuracağız.
``</p>

<p>Bunun için Linux çekirdeğinin trafik kontrol sistemi olan <code class="language-plaintext highlighter-rouge">tc</code> ve onun meşhur <code class="language-plaintext highlighter-rouge">netem</code> modülünü kullanacağız. <code class="language-plaintext highlighter-rouge">netem</code>, network emulator demektir; paketleri geciktirebilir, düşürebilir, çoğaltabilir, bozabilir veya yeniden sıralayabilir. Bizim hedefimiz şu: izole bir test alanı oluşturmak, uygulamayı bu alanın içinden çalıştırmak ve dış dünyaya çıkan/gelen trafiği bozmak.</p>

<p>Teorik olarak paket kaybını şöyle düşünebiliriz: Her paketin düşme olasılığı $p = 0.05$ ise, bir paketin başarıyla ulaşma olasılığı $1-p = 0.95$ olur. Art arda $n$ paketin tamamının ulaşma olasılığı ise:</p>

\[P(başarı) = (0.95)^n\]

<p>Yani 100 paketlik küçük bir aktarımda bile tamamının sorunsuz ulaşma ihtimali yaklaşık $0.95^{100} \approx 0.0059$ olur. Kısacası %5 kulağa az gelir ama protokoller ve kullanıcı deneyimi üzerinde ciddi etkisi vardır.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Ne yapar?</th>
      <th>Bizim senaryodaki rolü</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">veth</code></td>
      <td>İki uçlu sanal ethernet kablosu oluşturur</td>
      <td>Host ile test alanını bağlar</td>
    </tr>
    <tr>
      <td>Network namespace</td>
      <td>Ayrı ağ yığını sağlar</td>
      <td>Uygulamayı izole çalıştırır</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">tc</code></td>
      <td>Trafik kontrol aracıdır</td>
      <td>Kuralları uygular</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">netem</code></td>
      <td>Ağ davranışı taklit eder</td>
      <td>Kaybı ve gecikmeyi üretir</td>
    </tr>
  </tbody>
</table>

<p>Önce gerekli araçların kurulu olduğundan emin olalım. Debian/Ubuntu için:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt <span class="nb">install </span>iproute2 iputils-ping <span class="nt">-y</span>
</code></pre></div></div>

<p>Şimdi bir network namespace ve iki uçlu sanal arayüz oluşturalım. <code class="language-plaintext highlighter-rouge">bad0</code> host tarafında, <code class="language-plaintext highlighter-rouge">eth0</code> ise kötü ağ simülasyonunun içinde kalacak.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Test namespace oluştur</span>
<span class="nb">sudo </span>ip netns add badnet

<span class="c"># Sanal ethernet çifti oluştur</span>
<span class="nb">sudo </span>ip <span class="nb">link </span>add bad0 <span class="nb">type </span>veth peer name eth0

<span class="c"># eth0 ucunu namespace içine taşı</span>
<span class="nb">sudo </span>ip <span class="nb">link set </span>eth0 netns badnet

<span class="c"># IP adreslerini ver</span>
<span class="nb">sudo </span>ip addr add 10.10.0.1/24 dev bad0
<span class="nb">sudo </span>ip netns <span class="nb">exec </span>badnet ip addr add 10.10.0.2/24 dev eth0

<span class="c"># Arayüzleri ayağa kaldır</span>
<span class="nb">sudo </span>ip <span class="nb">link set </span>bad0 up
<span class="nb">sudo </span>ip netns <span class="nb">exec </span>badnet ip <span class="nb">link set </span>eth0 up
<span class="nb">sudo </span>ip netns <span class="nb">exec </span>badnet ip <span class="nb">link set </span>lo up
</code></pre></div></div>

<p>Bu noktada host ile namespace birbirini görebilir. Test edelim:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>ip netns <span class="nb">exec </span>badnet ping <span class="nt">-c</span> 3 10.10.0.1
</code></pre></div></div>

<p>Şimdi işin eğlenceli kısmı: paket kaybı ve gecikme. Gelen trafiği simüle etmek için host tarafındaki <code class="language-plaintext highlighter-rouge">bad0</code> arayüzünün namespace’e doğru gönderdiği paketlere kural ekleyeceğiz. Yani namespace açısından bu trafik “gelen paket” gibi davranır.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>tc qdisc add dev bad0 root netem loss 5% delay 120ms 60ms distribution normal
</code></pre></div></div>

<p>Bu komut şunu söyler: <code class="language-plaintext highlighter-rouge">bad0</code> üzerinden çıkan paketlerin %5’ini düşür, kalanlara ortalama 120 ms gecikme ekle, bu gecikmeyi 60 ms sapmayla rastgele dağıt. Basitçe gecikmeyi şöyle modelleyebiliriz:</p>

\[D = 120ms + X\]

<p>Burada $X$, normal dağılıma benzeyen rastgele bir sapmadır. Böylece her paket aynı sürede gelmez; gerçek ağlardaki “jitter” hissi oluşur.</p>

<table>
  <thead>
    <tr>
      <th>Ayar</th>
      <th>Etki</th>
      <th>Ne zaman kullanılır?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">loss 5%</code></td>
      <td>Paketlerin bir kısmı kaybolur</td>
      <td>Mobil ağ, zayıf Wi‑Fi testi</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">delay 120ms</code></td>
      <td>Sabit gecikme ekler</td>
      <td>Uzak sunucu simülasyonu</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">60ms</code></td>
      <td>Gecikmeyi rastgeleleştirir</td>
      <td>Jitter testi</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">distribution normal</code></td>
      <td>Daha doğal dağılım sağlar</td>
      <td>Gerçekçi testler</td>
    </tr>
  </tbody>
</table>

<p>Eğer namespace içindeki bir uygulamanın internete çıkmasını istiyorsanız IP forwarding ve NAT da ekleyebilirsiniz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>sysctl <span class="nt">-w</span> net.ipv4.ip_forward<span class="o">=</span>1
<span class="nb">sudo </span>ip netns <span class="nb">exec </span>badnet ip route add default via 10.10.0.1

<span class="c"># eth0 yerine internete çıkan gerçek arayüzünüzü yazın; örn: wlan0 veya enp3s0</span>
<span class="nb">sudo </span>iptables <span class="nt">-t</span> nat <span class="nt">-A</span> POSTROUTING <span class="nt">-s</span> 10.10.0.0/24 <span class="nt">-o</span> wlan0 <span class="nt">-j</span> MASQUERADE
</code></pre></div></div>

<p>Artık kötü ağın içinden komut çalıştırabilirsiniz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>ip netns <span class="nb">exec </span>badnet curl https://example.com
<span class="nb">sudo </span>ip netns <span class="nb">exec </span>badnet ping <span class="nt">-c</span> 20 8.8.8.8
</code></pre></div></div>

<p>Sonuçlarda zaman zaman paket kaybı ve değişken ping süreleri görmelisiniz. Web API istemciniz burada timeout, retry, circuit breaker ve kullanıcıya hata gösterme davranışları açısından güzelce sınanır.</p>

<p>Kuralları görmek için:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tc qdisc show dev bad0
</code></pre></div></div>

<p>Simülasyonu kaldırmak için:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>tc qdisc del dev bad0 root
<span class="nb">sudo </span>ip netns del badnet
<span class="nb">sudo </span>ip <span class="nb">link </span>del bad0 2&gt;/dev/null <span class="o">||</span> <span class="nb">true</span>
</code></pre></div></div>

<p>Bu kurulum küçük görünür ama gerçek hayatta çok değerlidir. Çünkü iyi yazılım sadece hızlı ağda çalışan yazılım değildir; paketler kaybolduğunda sakin kalabilen, gecikmede paniklemeyen ve kullanıcıya düzgün geri bildirim verebilen yazılımdır. Kısacası artık bilgisayarınızda minik, kontrollü ve biraz da huysuz bir internet servis sağlayıcınız var.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="linux" /><category term="networking" /><category term="tc-netem" /><category term="devops" /><category term="test" /><summary type="html"><![CDATA[Uygulamanız lokal makinede ışık hızında çalışıyor olabilir; peki kullanıcı metroda, otel Wi‑Fi’ında ya da yağmurlu bir günde 4G’deyken ne olacak? Bu yazıda Linux üzerinde sanal bir ağ arayüzü oluşturup gelen paketlere yapay olarak %5 paket kaybı ve rastgele gecikme ekleyen küçük ama çok faydalı bir “kötü ağ simülatörü” kuracağız.]]></summary></entry><entry><title type="html">Netfilter ile Kedi Görsellerini Ters Çeviren HTTP Proxy Modülü</title><link href="https://sonsuzus.github.io/posts/netfilter-ile-kedi-gorsellerini-ters-ceviren-http-proxy-modulu/" rel="alternate" type="text/html" title="Netfilter ile Kedi Görsellerini Ters Çeviren HTTP Proxy Modülü" /><published>2026-07-22T00:00:00+00:00</published><updated>2026-07-22T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/netfilter-ile-kedi-gorsellerini-ters-ceviren-http-proxy-modulu</id><content type="html" xml:base="https://sonsuzus.github.io/posts/netfilter-ile-kedi-gorsellerini-ters-ceviren-http-proxy-modulu/"><![CDATA[<p>Bazen yazılım projeleri ciddi bir problemi çözer; bazen de ağdan geçen kedi fotoğraflarını baş aşağı çevirerek ekip arkadaşlarını hafifçe şaşırtır. Bu yazıda Linux ağ alt sistemindeki netfilter kancalarına takılan, giden HTTP trafiğini yakalayan ve kedi görseli dönen yanıtları kullanıcı alanındaki küçük bir proxy ile ters çeviren deneysel bir modül tasarlıyoruz. Not: HTTPS şifreli olduğu için bu oyun yalnızca düz HTTP ve laboratuvar ortamı içindir.
``
Önce küçük bir gerçeklik kontrolü yapalım: Giden HTTP isteğinin içinde genellikle resim yoktur; istemci sadece <code class="language-plaintext highlighter-rouge">GET /cat.jpg</code> der. Resim, sunucudan gelen HTTP yanıtında bulunur. Bu yüzden mimarimiz iki parçalı olacak: kernel tarafında netfilter hook paketi işaretler veya kuyruğa alır, kullanıcı alanındaki proxy ise yanıt gövdesini okuyup gerekiyorsa görseli ters çevirir.</p>

<p>Netfilter, Linux kernel içinde paketlerin geçtiği kontrol noktaları sunar. Basitleştirilmiş akış şöyle düşünülebilir: paket üretildiğinde <code class="language-plaintext highlighter-rouge">LOCAL_OUT</code>, yönlendirilirken <code class="language-plaintext highlighter-rouge">FORWARD</code>, makineye girerken <code class="language-plaintext highlighter-rouge">LOCAL_IN</code> gibi kancalar devreye girer. Biz yerel makineden çıkan HTTP isteklerini hedeflediğimiz için <code class="language-plaintext highlighter-rouge">NF_INET_LOCAL_OUT</code> iyi bir başlangıçtır.</p>

<table>
  <thead>
    <tr>
      <th>Katman</th>
      <th>Görev</th>
      <th>Neden burada?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Netfilter hook</td>
      <td>TCP/80 paketini yakalar</td>
      <td>Kernel seviyesinde hızlı karar</td>
    </tr>
    <tr>
      <td>NFQUEUE veya mark</td>
      <td>Paketi proxy yoluna sokar</td>
      <td>Kernelde resim işlemek pahalıdır</td>
    </tr>
    <tr>
      <td>Kullanıcı alanı proxy</td>
      <td>HTTP yanıtını değiştirir</td>
      <td>Pillow gibi araçlar kullanılabilir</td>
    </tr>
    <tr>
      <td>Tarayıcı</td>
      <td>Değişmiş resmi görür</td>
      <td>Kullanıcıya sihir gibi gelir</td>
    </tr>
  </tbody>
</table>

<table>
  <tbody>
    <tr>
      <td>Teorik olarak karar fonksiyonumuzu şöyle yazabiliriz: $F(p) = 1$ ise paket proxyye gider, $F(p) = 0$ ise normal akar. Pratikte $F(p)$, hedef portun 80 olup olmadığına bakar. Kedi tespiti ise daha yukarı katmanda yapılır: URL içinde <code class="language-plaintext highlighter-rouge">cat</code>, <code class="language-plaintext highlighter-rouge">kitten</code>, <code class="language-plaintext highlighter-rouge">kedi</code> geçmesi veya <code class="language-plaintext highlighter-rouge">Content-Type: image/jpeg</code> gibi başlıkların görülmesi. Basit skor mantığıyla $P(cat</td>
      <td>url) = score/total$ diyebiliriz; eşik üstündeyse görsel çevrilir.</td>
    </tr>
  </tbody>
</table>

<p>Kernel tarafındaki iskelet kod, paketin TCP ve hedef portunun 80 olup olmadığını kontrol eder. Aşağıdaki örnek tam bir modül değil, mantığı gösteren orta seviye bir kesittir:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;linux/module.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;linux/netfilter.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;linux/netfilter_ipv4.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;linux/ip.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;linux/tcp.h&gt;</span><span class="cp">
</span>
<span class="k">static</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="nf">cat_hook</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">priv</span><span class="p">,</span>
    <span class="k">struct</span> <span class="n">sk_buff</span> <span class="o">*</span><span class="n">skb</span><span class="p">,</span>
    <span class="k">const</span> <span class="k">struct</span> <span class="n">nf_hook_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span> <span class="p">{</span>

    <span class="k">struct</span> <span class="n">iphdr</span> <span class="o">*</span><span class="n">iph</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">tcphdr</span> <span class="o">*</span><span class="n">tcph</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">skb</span><span class="p">)</span> <span class="k">return</span> <span class="n">NF_ACCEPT</span><span class="p">;</span>
    <span class="n">iph</span> <span class="o">=</span> <span class="n">ip_hdr</span><span class="p">(</span><span class="n">skb</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">iph</span> <span class="o">||</span> <span class="n">iph</span><span class="o">-&gt;</span><span class="n">protocol</span> <span class="o">!=</span> <span class="n">IPPROTO_TCP</span><span class="p">)</span> <span class="k">return</span> <span class="n">NF_ACCEPT</span><span class="p">;</span>

    <span class="n">tcph</span> <span class="o">=</span> <span class="n">tcp_hdr</span><span class="p">(</span><span class="n">skb</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">tcph</span><span class="p">)</span> <span class="k">return</span> <span class="n">NF_ACCEPT</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">ntohs</span><span class="p">(</span><span class="n">tcph</span><span class="o">-&gt;</span><span class="n">dest</span><span class="p">)</span> <span class="o">==</span> <span class="mi">80</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">skb</span><span class="o">-&gt;</span><span class="n">mark</span> <span class="o">=</span> <span class="mh">0xC47</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">NF_ACCEPT</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu işaret daha sonra <code class="language-plaintext highlighter-rouge">iptables</code> veya <code class="language-plaintext highlighter-rouge">nftables</code> ile yerel proxyye yönlendirilebilir. Örneğin işaretli paketleri 8080 portuna almak gibi. Kernel içinde HTTP ayrıştırmaya çalışmak cazip görünse de parçalanmış TCP akışı, checksum güncelleme, bellek güvenliği ve performans nedeniyle kullanıcı alanı çok daha sağlıklı bir yerdir.</p>

<p>Proxy tarafında mantık şudur: isteği gerçek sunucuya gönder, yanıt başlıklarını oku, gövde bir görselse belleğe al, ters çevir, <code class="language-plaintext highlighter-rouge">Content-Length</code> değerini güncelle ve istemciye dön. Python ile minik bir örnek:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">io</span> <span class="kn">import</span> <span class="n">BytesIO</span>
<span class="kn">from</span> <span class="n">PIL</span> <span class="kn">import</span> <span class="n">Image</span>

<span class="k">def</span> <span class="nf">flip_if_cat</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">headers</span><span class="p">,</span> <span class="n">body</span><span class="p">):</span>
    <span class="n">ctype</span> <span class="o">=</span> <span class="n">headers</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">'</span><span class="s">Content-Type</span><span class="sh">'</span><span class="p">,</span> <span class="sh">''</span><span class="p">)</span>
    <span class="n">looks_like_cat</span> <span class="o">=</span> <span class="nf">any</span><span class="p">(</span><span class="n">x</span> <span class="ow">in</span> <span class="n">url</span><span class="p">.</span><span class="nf">lower</span><span class="p">()</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">[</span><span class="sh">'</span><span class="s">cat</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">kitten</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">kedi</span><span class="sh">'</span><span class="p">])</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">looks_like_cat</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">headers</span><span class="p">,</span> <span class="n">body</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">ctype</span><span class="p">.</span><span class="nf">startswith</span><span class="p">(</span><span class="sh">'</span><span class="s">image/</span><span class="sh">'</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">headers</span><span class="p">,</span> <span class="n">body</span>

    <span class="n">img</span> <span class="o">=</span> <span class="n">Image</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="nc">BytesIO</span><span class="p">(</span><span class="n">body</span><span class="p">))</span>
    <span class="n">flipped</span> <span class="o">=</span> <span class="n">img</span><span class="p">.</span><span class="nf">transpose</span><span class="p">(</span><span class="n">Image</span><span class="p">.</span><span class="n">Transpose</span><span class="p">.</span><span class="n">FLIP_TOP_BOTTOM</span><span class="p">)</span>

    <span class="n">out</span> <span class="o">=</span> <span class="nc">BytesIO</span><span class="p">()</span>
    <span class="n">fmt</span> <span class="o">=</span> <span class="n">img</span><span class="p">.</span><span class="nb">format</span> <span class="ow">or</span> <span class="sh">'</span><span class="s">PNG</span><span class="sh">'</span>
    <span class="n">flipped</span><span class="p">.</span><span class="nf">save</span><span class="p">(</span><span class="n">out</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="n">fmt</span><span class="p">)</span>
    <span class="n">new_body</span> <span class="o">=</span> <span class="n">out</span><span class="p">.</span><span class="nf">getvalue</span><span class="p">()</span>

    <span class="n">headers</span><span class="p">[</span><span class="sh">'</span><span class="s">Content-Length</span><span class="sh">'</span><span class="p">]</span> <span class="o">=</span> <span class="nf">str</span><span class="p">(</span><span class="nf">len</span><span class="p">(</span><span class="n">new_body</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">headers</span><span class="p">,</span> <span class="n">new_body</span>
</code></pre></div></div>

<p>Buradaki en önemli ayrıntı, HTTP yanıtının sıkıştırılmış olabileceğidir. <code class="language-plaintext highlighter-rouge">Content-Encoding: gzip</code> varsa önce açmak, işlemden sonra tekrar sıkıştırmak gerekir. Ayrıca büyük görselleri tamamen belleğe almak yerine akış tabanlı işlemek daha güvenlidir. Deney ortamında ise <code class="language-plaintext highlighter-rouge">curl --proxy localhost:8080 http://site/cat.jpg</code> komutu ile hızlıca test yapılabilir.</p>

<table>
  <thead>
    <tr>
      <th>Problem</th>
      <th>Basit çözüm</th>
      <th>Üretim yaklaşımı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>HTTPS görünmez</td>
      <td>Sadece HTTP test et</td>
      <td>Kurumsal izinli MITM gerekir</td>
    </tr>
    <tr>
      <td>Büyük dosya</td>
      <td>Boyut limiti koy</td>
      <td>Streaming pipeline kullan</td>
    </tr>
    <tr>
      <td>Yanlış pozitif</td>
      <td>URL anahtarı ara</td>
      <td>Hafif ML sınıflandırıcı ekle</td>
    </tr>
  </tbody>
</table>

<p>Sonuç olarak bu proje, netfilterın paket seviyesindeki gücü ile kullanıcı alanındaki esnekliği eğlenceli bir şekilde birleştiriyor. Kernel sadece trafiği seçiyor, proxy ise HTTP ve görsel işleme gibi karmaşık işleri üstleniyor. Böylece hem Linux ağ mimarisini öğreniyor hem de internetin kedilerini kısa süreliğine baş aşağı izliyoruz.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="linux" /><category term="netfilter" /><category term="proxy" /><category term="http" /><category term="kernel" /><summary type="html"><![CDATA[Bazen yazılım projeleri ciddi bir problemi çözer; bazen de ağdan geçen kedi fotoğraflarını baş aşağı çevirerek ekip arkadaşlarını hafifçe şaşırtır. Bu yazıda Linux ağ alt sistemindeki netfilter kancalarına takılan, giden HTTP trafiğini yakalayan ve kedi görseli dönen yanıtları kullanıcı alanındaki küçük bir proxy ile ters çeviren deneysel bir modül tasarlıyoruz. Not: HTTPS şifreli olduğu için bu oyun yalnızca düz HTTP ve laboratuvar ortamı içindir.]]></summary></entry><entry><title type="html">Raspberry Pi Device Tree Sorgulayıcı: GPIO, I2C ve SPI Fiziksel Adreslerini Avlamak</title><link href="https://sonsuzus.github.io/posts/raspberry-pi-device-tree-sorgulayici-gpio-i2c-ve-spi-fiziksel-adreslerini-avlamak/" rel="alternate" type="text/html" title="Raspberry Pi Device Tree Sorgulayıcı: GPIO, I2C ve SPI Fiziksel Adreslerini Avlamak" /><published>2026-07-22T00:00:00+00:00</published><updated>2026-07-22T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/raspberry-pi-device-tree-sorgulayici-gpio-i2c-ve-spi-fiziksel-adreslerini-avlamak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/raspberry-pi-device-tree-sorgulayici-gpio-i2c-ve-spi-fiziksel-adreslerini-avlamak/"><![CDATA[<p>Raspberry Pi üzerinde GPIO, I2C, SPI ya da UART gibi çevre birimlerinin fiziksel adreslerini öğrenmek istiyorsan genelde datasheet, forum ve kernel kaynak kodu üçgeninde kaybolursun. Oysa Linux zaten bu bilgilerin büyük kısmını Device Tree üzerinden çekirdeğe sunar. Bu yazıda /proc/device-tree dosyalarını okuyarak çevre birimlerini ve adres aralıklarını listeleyen küçük ama güçlü bir sorgu aracı tasarlayacağız.
``</p>

<p>Device Tree, donanıma ait hiyerarşik bir tarif dosyasıdır. Kernel açılırken “şu adreste GPIO var”, “bu I2C kontrolcüsü şu kesmeyi kullanıyor” gibi bilgileri buradan okur. Raspberry Pi’de bu ağaç genellikle <code class="language-plaintext highlighter-rouge">/proc/device-tree</code> altında sanal dosya sistemi olarak görünür. Her klasör bir düğüm, her dosya ise bir özelliktir. Örneğin <code class="language-plaintext highlighter-rouge">compatible</code>, <code class="language-plaintext highlighter-rouge">status</code>, <code class="language-plaintext highlighter-rouge">reg</code> ve <code class="language-plaintext highlighter-rouge">ranges</code> en sık karşımıza çıkan özelliklerdir.</p>

<p>Buradaki asıl sihir <code class="language-plaintext highlighter-rouge">reg</code> alanındadır. Ancak <code class="language-plaintext highlighter-rouge">reg</code> düz bir sayı değildir; kaç hücreden oluşacağı üst düğümdeki <code class="language-plaintext highlighter-rouge">#address-cells</code> ve <code class="language-plaintext highlighter-rouge">#size-cells</code> değerlerine bağlıdır. Basitçe düşünürsek:</p>

\[reg = address_{cells} + size_{cells}\]

<p>Eğer <code class="language-plaintext highlighter-rouge">#address-cells = 1</code> ve <code class="language-plaintext highlighter-rouge">#size-cells = 1</code> ise <code class="language-plaintext highlighter-rouge">reg</code> içinde önce başlangıç adresi, ardından boyut gelir. Raspberry Pi SoC çevre birimleri çoğunlukla bellek eşlemeli I/O kullandığından, bu adresler CPU’nun fiziksel adres haritasına bağlanır. Yani GPIO’ya yazmak aslında belirli bir bellek adresine yazmaktır. Eğlenceli tarafı şu: LED yakmak, teoride RAM’e mektup bırakmak gibidir; sadece mektubu alan kişi bir GPIO kontrolcüsüdür.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Ne Anlama Gelir?</th>
      <th>Örnek</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Node</td>
      <td>Donanım bileşeni</td>
      <td><code class="language-plaintext highlighter-rouge">gpio@7e200000</code></td>
    </tr>
    <tr>
      <td>Property</td>
      <td>Düğüm bilgisi</td>
      <td><code class="language-plaintext highlighter-rouge">compatible</code>, <code class="language-plaintext highlighter-rouge">reg</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">reg</code></td>
      <td>Adres ve boyut</td>
      <td><code class="language-plaintext highlighter-rouge">0x7e200000 0xb4</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ranges</code></td>
      <td>Bus adresini CPU adresine çevirir</td>
      <td><code class="language-plaintext highlighter-rouge">0x7e000000 -&gt; 0xfe000000</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">status</code></td>
      <td>Aygıt aktif mi?</td>
      <td><code class="language-plaintext highlighter-rouge">okay</code>, <code class="language-plaintext highlighter-rouge">disabled</code></td>
    </tr>
  </tbody>
</table>

<p>Adres yorumlarken önemli bir ayrım vardır: Device Tree’de görülen bus adresi her zaman CPU fiziksel adresi olmayabilir. Özellikle Raspberry Pi modellerinde peripheral base adresi modele göre değişebilir. Örneğin eski modellerde <code class="language-plaintext highlighter-rouge">0x20000000</code>, Pi 2/3 tarafında <code class="language-plaintext highlighter-rouge">0x3f000000</code>, Pi 4 tarafında <code class="language-plaintext highlighter-rouge">0xfe000000</code> sık görülür. Device Tree’deki <code class="language-plaintext highlighter-rouge">ranges</code> alanı bu dönüşümün ipucunu verir.</p>

<table>
  <thead>
    <tr>
      <th>Raspberry Pi Nesli</th>
      <th style="text-align: right">Yaygın Peripheral Base</th>
      <th>Not</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Pi 1 / Zero</td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">0x20000000</code></td>
      <td>BCM2835</td>
    </tr>
    <tr>
      <td>Pi 2 / Pi 3</td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">0x3f000000</code></td>
      <td>BCM2836/2837</td>
    </tr>
    <tr>
      <td>Pi 4</td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">0xfe000000</code></td>
      <td>BCM2711</td>
    </tr>
  </tbody>
</table>

<p>Şimdi Python ile bir tarayıcı yazalım. Amaç: <code class="language-plaintext highlighter-rouge">/proc/device-tree</code> altında gezmek, <code class="language-plaintext highlighter-rouge">compatible</code> veya düğüm adına göre GPIO/I2C/SPI adaylarını bulmak, <code class="language-plaintext highlighter-rouge">reg</code> alanını okuyup adresleri hesaplamak.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
<span class="kn">import</span> <span class="n">struct</span>

<span class="n">DT</span> <span class="o">=</span> <span class="nc">Path</span><span class="p">(</span><span class="sh">'</span><span class="s">/proc/device-tree</span><span class="sh">'</span><span class="p">)</span>
<span class="n">KEYWORDS</span> <span class="o">=</span> <span class="p">(</span><span class="sh">'</span><span class="s">gpio</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">i2c</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">spi</span><span class="sh">'</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">read_prop</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">path</span><span class="p">.</span><span class="nf">read_bytes</span><span class="p">()</span>
    <span class="k">except</span> <span class="nb">FileNotFoundError</span><span class="p">:</span>
        <span class="k">return</span> <span class="bp">None</span>

<span class="k">def</span> <span class="nf">read_u32_cells</span><span class="p">(</span><span class="n">prop</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">prop</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">[]</span>
    <span class="n">count</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">prop</span><span class="p">)</span> <span class="o">//</span> <span class="mi">4</span>
    <span class="k">return</span> <span class="nf">list</span><span class="p">(</span><span class="n">struct</span><span class="p">.</span><span class="nf">unpack</span><span class="p">(</span><span class="sh">'</span><span class="s">&gt;</span><span class="sh">'</span> <span class="o">+</span> <span class="sh">'</span><span class="s">I</span><span class="sh">'</span> <span class="o">*</span> <span class="n">count</span><span class="p">,</span> <span class="n">prop</span><span class="p">[:</span><span class="n">count</span> <span class="o">*</span> <span class="mi">4</span><span class="p">]))</span>

<span class="k">def</span> <span class="nf">read_text</span><span class="p">(</span><span class="n">prop</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">prop</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">''</span>
    <span class="k">return</span> <span class="n">prop</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sa">b</span><span class="sh">'</span><span class="se">\x00</span><span class="sh">'</span><span class="p">,</span> <span class="sa">b</span><span class="sh">'</span><span class="s">,</span><span class="sh">'</span><span class="p">).</span><span class="nf">decode</span><span class="p">(</span><span class="n">errors</span><span class="o">=</span><span class="sh">'</span><span class="s">ignore</span><span class="sh">'</span><span class="p">).</span><span class="nf">strip</span><span class="p">(</span><span class="sh">'</span><span class="s">,</span><span class="sh">'</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">get_cells</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">default</span><span class="p">):</span>
    <span class="n">current</span> <span class="o">=</span> <span class="n">node</span>
    <span class="k">while</span> <span class="n">current</span> <span class="o">!=</span> <span class="n">current</span><span class="p">.</span><span class="n">parent</span><span class="p">:</span>
        <span class="n">value</span> <span class="o">=</span> <span class="nf">read_prop</span><span class="p">(</span><span class="n">current</span> <span class="o">/</span> <span class="n">name</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">value</span><span class="p">:</span>
            <span class="n">cells</span> <span class="o">=</span> <span class="nf">read_u32_cells</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">cells</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">cells</span> <span class="k">else</span> <span class="n">default</span>
        <span class="n">current</span> <span class="o">=</span> <span class="n">current</span><span class="p">.</span><span class="n">parent</span>
    <span class="k">return</span> <span class="n">default</span>

<span class="k">def</span> <span class="nf">parse_reg</span><span class="p">(</span><span class="n">node</span><span class="p">):</span>
    <span class="n">reg</span> <span class="o">=</span> <span class="nf">read_u32_cells</span><span class="p">(</span><span class="nf">read_prop</span><span class="p">(</span><span class="n">node</span> <span class="o">/</span> <span class="sh">'</span><span class="s">reg</span><span class="sh">'</span><span class="p">))</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">reg</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">[]</span>

    <span class="n">parent</span> <span class="o">=</span> <span class="n">node</span><span class="p">.</span><span class="n">parent</span>
    <span class="n">addr_cells</span> <span class="o">=</span> <span class="nf">get_cells</span><span class="p">(</span><span class="n">parent</span><span class="p">,</span> <span class="sh">'</span><span class="s">#address-cells</span><span class="sh">'</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
    <span class="n">size_cells</span> <span class="o">=</span> <span class="nf">get_cells</span><span class="p">(</span><span class="n">parent</span><span class="p">,</span> <span class="sh">'</span><span class="s">#size-cells</span><span class="sh">'</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
    <span class="n">step</span> <span class="o">=</span> <span class="n">addr_cells</span> <span class="o">+</span> <span class="n">size_cells</span>
    <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nf">len</span><span class="p">(</span><span class="n">reg</span><span class="p">),</span> <span class="n">step</span><span class="p">):</span>
        <span class="n">addr</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="n">size</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">for</span> <span class="n">cell</span> <span class="ow">in</span> <span class="n">reg</span><span class="p">[</span><span class="n">i</span><span class="p">:</span><span class="n">i</span> <span class="o">+</span> <span class="n">addr_cells</span><span class="p">]:</span>
            <span class="n">addr</span> <span class="o">=</span> <span class="p">(</span><span class="n">addr</span> <span class="o">&lt;&lt;</span> <span class="mi">32</span><span class="p">)</span> <span class="o">|</span> <span class="n">cell</span>
        <span class="k">for</span> <span class="n">cell</span> <span class="ow">in</span> <span class="n">reg</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">addr_cells</span><span class="p">:</span><span class="n">i</span> <span class="o">+</span> <span class="n">step</span><span class="p">]:</span>
            <span class="n">size</span> <span class="o">=</span> <span class="p">(</span><span class="n">size</span> <span class="o">&lt;&lt;</span> <span class="mi">32</span><span class="p">)</span> <span class="o">|</span> <span class="n">cell</span>
        <span class="n">results</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">addr</span><span class="p">,</span> <span class="n">size</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">results</span>

<span class="k">def</span> <span class="nf">scan</span><span class="p">():</span>
    <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">DT</span><span class="p">.</span><span class="nf">rglob</span><span class="p">(</span><span class="sh">'</span><span class="s">*</span><span class="sh">'</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">node</span><span class="p">.</span><span class="nf">is_dir</span><span class="p">():</span>
            <span class="k">continue</span>
        <span class="n">name</span> <span class="o">=</span> <span class="n">node</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="nf">lower</span><span class="p">()</span>
        <span class="n">compatible</span> <span class="o">=</span> <span class="nf">read_text</span><span class="p">(</span><span class="nf">read_prop</span><span class="p">(</span><span class="n">node</span> <span class="o">/</span> <span class="sh">'</span><span class="s">compatible</span><span class="sh">'</span><span class="p">)).</span><span class="nf">lower</span><span class="p">()</span>
        <span class="k">if</span> <span class="nf">any</span><span class="p">(</span><span class="n">k</span> <span class="ow">in</span> <span class="n">name</span> <span class="ow">or</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">compatible</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">KEYWORDS</span><span class="p">):</span>
            <span class="n">regs</span> <span class="o">=</span> <span class="nf">parse_reg</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
            <span class="n">status</span> <span class="o">=</span> <span class="nf">read_text</span><span class="p">(</span><span class="nf">read_prop</span><span class="p">(</span><span class="n">node</span> <span class="o">/</span> <span class="sh">'</span><span class="s">status</span><span class="sh">'</span><span class="p">))</span> <span class="ow">or</span> <span class="sh">'</span><span class="s">okay?</span><span class="sh">'</span>
            <span class="k">if</span> <span class="n">regs</span><span class="p">:</span>
                <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="s">[</span><span class="si">{</span><span class="n">status</span><span class="si">}</span><span class="s">] </span><span class="si">{</span><span class="n">node</span><span class="p">.</span><span class="nf">relative_to</span><span class="p">(</span><span class="n">DT</span><span class="p">)</span><span class="si">}</span><span class="sh">'</span><span class="p">)</span>
                <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="s">  compatible: </span><span class="si">{</span><span class="n">compatible</span><span class="si">}</span><span class="sh">'</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">addr</span><span class="p">,</span> <span class="n">size</span> <span class="ow">in</span> <span class="n">regs</span><span class="p">:</span>
                    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">'</span><span class="s">  reg: 0x</span><span class="si">{</span><span class="n">addr</span><span class="si">:</span><span class="mi">08</span><span class="n">x</span><span class="si">}</span><span class="s"> size=0x</span><span class="si">{</span><span class="n">size</span><span class="si">:</span><span class="n">x</span><span class="si">}</span><span class="sh">'</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="sh">'</span><span class="s">__main__</span><span class="sh">'</span><span class="p">:</span>
    <span class="nf">scan</span><span class="p">()</span>
</code></pre></div></div>

<p>Kodun yaptığı şey oldukça mekanik: dosyaları byte olarak okuyor, Device Tree hücreleri big-endian olduğu için <code class="language-plaintext highlighter-rouge">struct.unpack('&gt;I')</code> kullanıyor ve <code class="language-plaintext highlighter-rouge">reg</code> alanını üst düğümdeki hücre sayılarına göre parçalıyor. Burada dikkat edilmesi gereken nokta, çıktıdaki adresin her zaman nihai CPU fiziksel adresi olmayabileceğidir. Daha ileri sürümde <code class="language-plaintext highlighter-rouge">ranges</code> ayrıştırması ekleyerek bus adresinden fiziksel adrese dönüşüm yapabiliriz.</p>

<p>Mini aracın örnek çıktısı şöyle görünebilir:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[okay] soc/gpio@7e200000
  compatible: brcm,bcm2711-gpio
  reg: 0x7e200000 size=0xb4

[okay] soc/i2c@7e804000
  compatible: brcm,bcm2711-i2c
  reg: 0x7e804000 size=0x1000
</code></pre></div></div>

<p>Bu proje bize iki önemli şey öğretir: Linux altında donanım bilgisi çoğu zaman zaten elimizin altındadır ve “adres” dediğimiz şey bağlama göre değişir. Device Tree okuma aracı, gömülü Linux dünyasında debugging için İsviçre çakısı gibidir. Bir sonraki adımda çıktıyı JSON’a çevirip web arayüzü ekleyebilir, hatta <code class="language-plaintext highlighter-rouge">devmem</code> ile güvenli salt-okunur register inceleme modülü yazabilirsin.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="raspberry-pi" /><category term="device-tree" /><category term="linux" /><category term="gpio" /><category term="python" /><summary type="html"><![CDATA[Raspberry Pi üzerinde GPIO, I2C, SPI ya da UART gibi çevre birimlerinin fiziksel adreslerini öğrenmek istiyorsan genelde datasheet, forum ve kernel kaynak kodu üçgeninde kaybolursun. Oysa Linux zaten bu bilgilerin büyük kısmını Device Tree üzerinden çekirdeğe sunar. Bu yazıda /proc/device-tree dosyalarını okuyarak çevre birimlerini ve adres aralıklarını listeleyen küçük ama güçlü bir sorgu aracı tasarlayacağız.]]></summary></entry><entry><title type="html">Sanal Seri Portla Eski Usul Modem Sohbeti: İki Process’i Konuşturmak</title><link href="https://sonsuzus.github.io/posts/sanal-seri-portla-eski-usul-modem-sohbeti-iki-processi-konusturmak/" rel="alternate" type="text/html" title="Sanal Seri Portla Eski Usul Modem Sohbeti: İki Process’i Konuşturmak" /><published>2026-07-22T00:00:00+00:00</published><updated>2026-07-22T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/sanal-seri-portla-eski-usul-modem-sohbeti-iki-processi-konusturmak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/sanal-seri-portla-eski-usul-modem-sohbeti-iki-processi-konusturmak/"><![CDATA[<p>Bir zamanlar internete bağlanmak, kulak tırmalayan bir modem serenadı eşliğinde gerçekleşirdi. Bugün TCP soketleri, REST API’leri ve mesaj kuyruklarıyla yaşıyoruz; ama iki process arasında sanal seri port çifti kurup bir taraftan AT komutları gönderirken diğer taraftan cevap okumak, haberleşmenin temel mantığını anlamak için hâlâ şahane bir laboratuvar deneyidir.
``</p>

<h2 id="fikir-kablo-yok-ama-seri-hat-var">Fikir: Kablo Yok, Ama Seri Hat Var</h2>

<p>Seri port haberleşmesi temelde baytların sırayla akmasıdır. Bir uç yazar, diğer uç okur. Gerçek dünyada bu iki ucu RS-232 kablosu bağlar; sanal dünyada ise işletim sistemi içinde oluşturulan bir port çifti bağlar. Linux’ta bunun için en pratik araçlardan biri <code class="language-plaintext highlighter-rouge">socat</code>tır. Windows tarafında benzer fikir için com0com, macOS/Linux tarafında ise <code class="language-plaintext highlighter-rouge">socat</code> veya <code class="language-plaintext highlighter-rouge">tty0tty</code> kullanılabilir.</p>

<p>Seri haberleşmede sık duyulan <code class="language-plaintext highlighter-rouge">9600 8N1</code> ifadesi şunu anlatır: saniyede 9600 bit, 8 veri biti, parity yok, 1 stop biti. Aslında her karakter yalnızca 8 bit değildir; start ve stop bitleriyle birlikte yaklaşık 10 bit taşınır. Bu yüzden teorik karakter hızı yaklaşık $9600 / 10 = 960$ byte/s olur. Genel olarak $R_{byte} \approx \frac{baud}{start + data + parity + stop}$ diyebiliriz.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Eski modem dünyası</th>
      <th>Sanal seri port dünyası</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Fiziksel hat</td>
      <td>Telefon kablosu</td>
      <td>İşletim sistemi içi PTY</td>
    </tr>
    <tr>
      <td>Komut dili</td>
      <td>AT komutları</td>
      <td>Bizim taklit ettiğimiz metin protokolü</td>
    </tr>
    <tr>
      <td>Gecikme</td>
      <td>Hat kalitesi ve modem</td>
      <td>Process zamanlaması</td>
    </tr>
    <tr>
      <td>Hata kaynağı</td>
      <td>Gürültü, kopma</td>
      <td>Buffer, timeout, yanlış ayar</td>
    </tr>
  </tbody>
</table>

<h2 id="sanal-port-çiftini-kurmak">Sanal Port Çiftini Kurmak</h2>

<p>Linux’ta iki uçlu sahte bir seri kabloyu şöyle oluşturabiliriz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>socat <span class="nt">-d</span> <span class="nt">-d</span> pty,raw,echo<span class="o">=</span>0,link<span class="o">=</span>/tmp/ttyV0 pty,raw,echo<span class="o">=</span>0,link<span class="o">=</span>/tmp/ttyV1
</code></pre></div></div>

<p>Bu komut <code class="language-plaintext highlighter-rouge">/tmp/ttyV0</code> ve <code class="language-plaintext highlighter-rouge">/tmp/ttyV1</code> adında iki sanal uç üretir. Birine yazılan veri diğerinden okunur. <code class="language-plaintext highlighter-rouge">raw</code> modu karakterleri pişirmeden geçirir, <code class="language-plaintext highlighter-rouge">echo=0</code> ise yazdığımız karakterlerin aynı uçtan geri dönmesini engeller. Gerekirse ayarları klasik terminal aracıyla da sabitleyebiliriz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">stty</span> <span class="nt">-F</span> /tmp/ttyV0 9600 cs8 <span class="nt">-cstopb</span> <span class="nt">-parenb</span> raw <span class="nt">-echo</span>
<span class="nb">stty</span> <span class="nt">-F</span> /tmp/ttyV1 9600 cs8 <span class="nt">-cstopb</span> <span class="nt">-parenb</span> raw <span class="nt">-echo</span>
</code></pre></div></div>

<h2 id="process-1-komut-gönderen-terminal">Process 1: Komut Gönderen Terminal</h2>

<p>Aşağıdaki Python betiği kendini eski bir terminal programı gibi davranmaya zorlar. <code class="language-plaintext highlighter-rouge">ATZ</code>, <code class="language-plaintext highlighter-rouge">ATI</code> ve <code class="language-plaintext highlighter-rouge">ATD5551234</code> komutlarını sırayla yollar, gelen cevapları okur.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">serial</span>
<span class="kn">import</span> <span class="n">time</span>

<span class="n">port</span> <span class="o">=</span> <span class="n">serial</span><span class="p">.</span><span class="nc">Serial</span><span class="p">(</span><span class="sh">'</span><span class="s">/tmp/ttyV0</span><span class="sh">'</span><span class="p">,</span> <span class="mi">9600</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>

<span class="n">commands</span> <span class="o">=</span> <span class="p">[</span><span class="sa">b</span><span class="sh">'</span><span class="s">ATZ</span><span class="se">\r</span><span class="sh">'</span><span class="p">,</span> <span class="sa">b</span><span class="sh">'</span><span class="s">ATI</span><span class="se">\r</span><span class="sh">'</span><span class="p">,</span> <span class="sa">b</span><span class="sh">'</span><span class="s">ATD5551234</span><span class="se">\r</span><span class="sh">'</span><span class="p">]</span>

<span class="k">for</span> <span class="n">cmd</span> <span class="ow">in</span> <span class="n">commands</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">Gonderiliyor:</span><span class="sh">'</span><span class="p">,</span> <span class="n">cmd</span><span class="p">)</span>
    <span class="n">port</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span>
    <span class="n">time</span><span class="p">.</span><span class="nf">sleep</span><span class="p">(</span><span class="mf">0.2</span><span class="p">)</span>
    <span class="n">response</span> <span class="o">=</span> <span class="n">port</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="mi">128</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">Cevap:</span><span class="sh">'</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span>

<span class="n">port</span><span class="p">.</span><span class="nf">close</span><span class="p">()</span>
</code></pre></div></div>

<p>Burada önemli nokta satır sonudur. Modemler genellikle komutun bittiğini carriage return, yani <code class="language-plaintext highlighter-rouge">\r</code> ile anlar. Modern metin dosyalarındaki <code class="language-plaintext highlighter-rouge">\n</code> alışkanlığı seri dünyada her zaman yeterli değildir.</p>

<h2 id="process-2-modem-rolü-yapan-okuyucu">Process 2: Modem Rolü Yapan Okuyucu</h2>

<p>İkinci process diğer ucu dinler. Gelen komutu buffer’a alır, <code class="language-plaintext highlighter-rouge">\r</code> görünce işler ve uygun cevabı üretir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">serial</span>

<span class="n">modem</span> <span class="o">=</span> <span class="n">serial</span><span class="p">.</span><span class="nc">Serial</span><span class="p">(</span><span class="sh">'</span><span class="s">/tmp/ttyV1</span><span class="sh">'</span><span class="p">,</span> <span class="mi">9600</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">buffer</span> <span class="o">=</span> <span class="sa">b</span><span class="sh">''</span>

<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
    <span class="n">b</span> <span class="o">=</span> <span class="n">modem</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">b</span><span class="p">:</span>
        <span class="k">continue</span>

    <span class="nb">buffer</span> <span class="o">+=</span> <span class="n">b</span>
    <span class="k">if</span> <span class="n">b</span> <span class="o">==</span> <span class="sa">b</span><span class="sh">'</span><span class="se">\r</span><span class="sh">'</span><span class="p">:</span>
        <span class="n">command</span> <span class="o">=</span> <span class="nb">buffer</span><span class="p">.</span><span class="nf">strip</span><span class="p">().</span><span class="nf">upper</span><span class="p">()</span>
        <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">Komut alindi:</span><span class="sh">'</span><span class="p">,</span> <span class="n">command</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">command</span> <span class="o">==</span> <span class="sa">b</span><span class="sh">'</span><span class="s">ATZ</span><span class="sh">'</span><span class="p">:</span>
            <span class="n">modem</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="sa">b</span><span class="sh">'</span><span class="s">OK</span><span class="se">\r\n</span><span class="sh">'</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">command</span> <span class="o">==</span> <span class="sa">b</span><span class="sh">'</span><span class="s">ATI</span><span class="sh">'</span><span class="p">:</span>
            <span class="n">modem</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="sa">b</span><span class="sh">'</span><span class="s">VIRTUAL MODEM 1.0</span><span class="se">\r\n</span><span class="s">OK</span><span class="se">\r\n</span><span class="sh">'</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">command</span><span class="p">.</span><span class="nf">startswith</span><span class="p">(</span><span class="sa">b</span><span class="sh">'</span><span class="s">ATD</span><span class="sh">'</span><span class="p">):</span>
            <span class="n">modem</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="sa">b</span><span class="sh">'</span><span class="s">CONNECT 9600</span><span class="se">\r\n</span><span class="sh">'</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">modem</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="sa">b</span><span class="sh">'</span><span class="s">ERROR</span><span class="se">\r\n</span><span class="sh">'</span><span class="p">)</span>

        <span class="nb">buffer</span> <span class="o">=</span> <span class="sa">b</span><span class="sh">''</span>
</code></pre></div></div>

<p>Bu küçük döngü aslında protokol tasarımının minyatür hâlidir: veri birikir, ayraç görülür, mesaj çözümlenir, cevap üretilir. TCP’de paketler, HTTP’de header’lar, MQTT’de frame’ler neyse; burada da <code class="language-plaintext highlighter-rouge">\r</code> odur.</p>

<h2 id="neden-bu-deney-değerli">Neden Bu Deney Değerli?</h2>

<p>Çünkü süreçler arası haberleşmeyi sihir olmaktan çıkarır. Bir API çağrısı da özünde kuralları belirlenmiş bayt alışverişidir. Burada hız, çerçeveleme ve zaman aşımı açıkça görünür. Baud rate düşükse kuyruk dolar; timeout kısa ise cevap kaçırılır; satır sonu yanlışsa modem sonsuza kadar bekler.</p>

<p>Küçük bir nostalji projesi gibi görünse de bu yöntem gömülü sistem testlerinde, donanım olmadan firmware simülasyonunda ve eski cihaz protokollerini tersine mühendislikle anlamada çok işe yarar. Üstelik iki process’i konuştururken duyulmayan o modem cızırtısını zihniniz otomatik tamamlar: cııııııık, hrrr, bıp… CONNECT 9600!</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="seri-port" /><category term="socat" /><category term="python" /><category term="modem" /><category term="process-communication" /><summary type="html"><![CDATA[Bir zamanlar internete bağlanmak, kulak tırmalayan bir modem serenadı eşliğinde gerçekleşirdi. Bugün TCP soketleri, REST API’leri ve mesaj kuyruklarıyla yaşıyoruz; ama iki process arasında sanal seri port çifti kurup bir taraftan AT komutları gönderirken diğer taraftan cevap okumak, haberleşmenin temel mantığını anlamak için hâlâ şahane bir laboratuvar deneyidir.]]></summary></entry><entry><title type="html">Terminalde ANSI Kaçış Kodlarıyla Gerçek Zamanlı Yılan Oyunu</title><link href="https://sonsuzus.github.io/posts/terminalde-ansi-kacis-kodlariyla-gercek-zamanli-yilan-oyunu/" rel="alternate" type="text/html" title="Terminalde ANSI Kaçış Kodlarıyla Gerçek Zamanlı Yılan Oyunu" /><published>2026-07-22T00:00:00+00:00</published><updated>2026-07-22T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/terminalde-ansi-kacis-kodlariyla-gercek-zamanli-yilan-oyunu</id><content type="html" xml:base="https://sonsuzus.github.io/posts/terminalde-ansi-kacis-kodlariyla-gercek-zamanli-yilan-oyunu/"><![CDATA[<p>Terminali sadece komut yazılan siyah bir kutu sanıyorsan, bugün biraz sihir yapıyoruz: ANSI kaçış kodlarıyla imleci piksel gibi oynatıp, renkleri değiştirip, gerçek zamanlı bir yılan oyunu tasarlayacağız. Buradaki amaç yalnızca “Snake yaptık” demek değil; terminalin nasıl çizim alanına dönüştüğünü, klavye girişinin nasıl anlık okunduğunu ve oyun döngüsünün nasıl çalıştığını anlamak.
``
ANSI kaçış kodları, terminale “şuraya git”, “rengi kırmızı yap”, “ekranı temizle” gibi komutlar gönderen özel metin dizileridir. Genelde <code class="language-plaintext highlighter-rouge">\x1b[</code> ile başlarlar. Buradaki <code class="language-plaintext highlighter-rouge">\x1b</code>, ESC karakteridir. Örneğin <code class="language-plaintext highlighter-rouge">\x1b[2J</code> ekranı temizler, <code class="language-plaintext highlighter-rouge">\x1b[10;20H</code> imleci 10. satır 20. sütuna taşır. Yani terminalde grafik çizmenin en temel fikri şudur: karakterleri doğru koordinatlara basmak.</p>

<p>Yılan oyununu modellemek için birkaç kavram yeterlidir. Yılanın gövdesi koordinat çiftlerinden oluşan bir listedir: <code class="language-plaintext highlighter-rouge">[(x1,y1), (x2,y2), ...]</code>. Her karede baş, mevcut yöne göre ilerler. Matematiksel olarak bunu şöyle düşünebiliriz: $p_{t+1}=p_t+v_t$. Burada $p$ konum, $v$ ise yöndür. Sağ için $(1,0)$, sol için $(-1,0)$, aşağı için $(0,1)$ kullanırız. Kenarlardan geçişli bir harita istersek yeni konumu mod ile hesaplarız: $x=(x+dx) \bmod W$.</p>

<table>
  <thead>
    <tr>
      <th>ANSI kodu</th>
      <th>Görevi</th>
      <th>Oyundaki kullanımı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">\x1b[2J</code></td>
      <td>Ekranı temizler</td>
      <td>Başlangıçta alanı sıfırlar</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">\x1b[?25l</code></td>
      <td>İmleci gizler</td>
      <td>Daha temiz görüntü sağlar</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">\x1b[y;xH</code></td>
      <td>İmleci taşır</td>
      <td>Yılan ve yem çizimi</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">\x1b[32m</code></td>
      <td>Yeşil renk</td>
      <td>Yılan gövdesi</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">\x1b[0m</code></td>
      <td>Stili sıfırlar</td>
      <td>Renk sızıntısını engeller</td>
    </tr>
  </tbody>
</table>

<p>Gerçek zamanlılık için klasik <code class="language-plaintext highlighter-rouge">input()</code> kullanamayız; çünkü Enter bekler. Python’da terminali “raw mode”a alarak tuşları anında okuyabiliriz. Aşağıdaki örnek, Linux/macOS terminallerinde çalışacak sade bir çekirdektir. Windows tarafında ANSI desteği yeni terminallerde vardır, fakat anlık tuş okuma için ek uyarlama gerekebilir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">sys</span><span class="p">,</span> <span class="n">time</span><span class="p">,</span> <span class="n">random</span><span class="p">,</span> <span class="n">select</span><span class="p">,</span> <span class="n">tty</span><span class="p">,</span> <span class="n">termios</span>

<span class="n">W</span><span class="p">,</span> <span class="n">H</span> <span class="o">=</span> <span class="mi">40</span><span class="p">,</span> <span class="mi">20</span>
<span class="n">ESC</span> <span class="o">=</span> <span class="sh">'</span><span class="se">\x1b</span><span class="s">[</span><span class="sh">'</span>

<span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
    <span class="k">return</span> <span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">ESC</span><span class="si">}{</span><span class="n">y</span><span class="si">}</span><span class="s">;</span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="s">H</span><span class="sh">'</span>

<span class="k">def</span> <span class="nf">color</span><span class="p">(</span><span class="n">c</span><span class="p">):</span>
    <span class="k">return</span> <span class="sa">f</span><span class="sh">'</span><span class="si">{</span><span class="n">ESC</span><span class="si">}{</span><span class="n">c</span><span class="si">}</span><span class="s">m</span><span class="sh">'</span>

<span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="n">snake</span><span class="p">,</span> <span class="n">food</span><span class="p">,</span> <span class="n">score</span><span class="p">):</span>
    <span class="n">out</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="n">out</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="nf">move</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="nf">color</span><span class="p">(</span><span class="mi">36</span><span class="p">)</span> <span class="o">+</span> <span class="sa">f</span><span class="sh">'</span><span class="s">Skor: </span><span class="si">{</span><span class="n">score</span><span class="si">}</span><span class="sh">'</span> <span class="o">+</span> <span class="nf">color</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span>
    <span class="n">out</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="nf">move</span><span class="p">(</span><span class="n">food</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">food</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="nf">color</span><span class="p">(</span><span class="mi">31</span><span class="p">)</span> <span class="o">+</span> <span class="sh">'</span><span class="s">●</span><span class="sh">'</span> <span class="o">+</span> <span class="nf">color</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span>
    <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">snake</span><span class="p">):</span>
        <span class="n">ch</span> <span class="o">=</span> <span class="sh">'</span><span class="s">◎</span><span class="sh">'</span> <span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="sh">'</span><span class="s">■</span><span class="sh">'</span>
        <span class="n">out</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="nf">move</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="o">+</span> <span class="nf">color</span><span class="p">(</span><span class="mi">32</span><span class="p">)</span> <span class="o">+</span> <span class="n">ch</span> <span class="o">+</span> <span class="nf">color</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span>
    <span class="n">sys</span><span class="p">.</span><span class="n">stdout</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="sh">''</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">out</span><span class="p">))</span>
    <span class="n">sys</span><span class="p">.</span><span class="n">stdout</span><span class="p">.</span><span class="nf">flush</span><span class="p">()</span>

<span class="k">def</span> <span class="nf">read_key</span><span class="p">():</span>
    <span class="k">if</span> <span class="n">select</span><span class="p">.</span><span class="nf">select</span><span class="p">([</span><span class="n">sys</span><span class="p">.</span><span class="n">stdin</span><span class="p">],</span> <span class="p">[],</span> <span class="p">[],</span> <span class="mi">0</span><span class="p">)[</span><span class="mi">0</span><span class="p">]:</span>
        <span class="k">return</span> <span class="n">sys</span><span class="p">.</span><span class="n">stdin</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="k">return</span> <span class="bp">None</span>

<span class="n">old</span> <span class="o">=</span> <span class="n">termios</span><span class="p">.</span><span class="nf">tcgetattr</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">stdin</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
    <span class="n">tty</span><span class="p">.</span><span class="nf">setcbreak</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">stdin</span><span class="p">)</span>
    <span class="n">sys</span><span class="p">.</span><span class="n">stdout</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="n">ESC</span> <span class="o">+</span> <span class="sh">'</span><span class="s">2J</span><span class="sh">'</span> <span class="o">+</span> <span class="n">ESC</span> <span class="o">+</span> <span class="sh">'</span><span class="s">?25l</span><span class="sh">'</span><span class="p">)</span>

    <span class="n">snake</span> <span class="o">=</span> <span class="p">[(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span> <span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span> <span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">10</span><span class="p">)]</span>
    <span class="n">direction</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
    <span class="n">food</span> <span class="o">=</span> <span class="p">(</span><span class="n">random</span><span class="p">.</span><span class="nf">randint</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">W</span><span class="p">),</span> <span class="n">random</span><span class="p">.</span><span class="nf">randint</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">H</span><span class="p">))</span>
    <span class="n">score</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
        <span class="n">key</span> <span class="o">=</span> <span class="nf">read_key</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">key</span> <span class="o">==</span> <span class="sh">'</span><span class="s">q</span><span class="sh">'</span><span class="p">:</span> <span class="k">break</span>
        <span class="k">if</span> <span class="n">key</span> <span class="o">==</span> <span class="sh">'</span><span class="s">w</span><span class="sh">'</span> <span class="ow">and</span> <span class="n">direction</span> <span class="o">!=</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">):</span> <span class="n">direction</span> <span class="o">=</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">key</span> <span class="o">==</span> <span class="sh">'</span><span class="s">s</span><span class="sh">'</span> <span class="ow">and</span> <span class="n">direction</span> <span class="o">!=</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span> <span class="n">direction</span> <span class="o">=</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">key</span> <span class="o">==</span> <span class="sh">'</span><span class="s">a</span><span class="sh">'</span> <span class="ow">and</span> <span class="n">direction</span> <span class="o">!=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">):</span> <span class="n">direction</span> <span class="o">=</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">key</span> <span class="o">==</span> <span class="sh">'</span><span class="s">d</span><span class="sh">'</span> <span class="ow">and</span> <span class="n">direction</span> <span class="o">!=</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">):</span> <span class="n">direction</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

        <span class="n">hx</span><span class="p">,</span> <span class="n">hy</span> <span class="o">=</span> <span class="n">snake</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
        <span class="n">dx</span><span class="p">,</span> <span class="n">dy</span> <span class="o">=</span> <span class="n">direction</span>
        <span class="n">head</span> <span class="o">=</span> <span class="p">((</span><span class="n">hx</span> <span class="o">+</span> <span class="n">dx</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">W</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="p">(</span><span class="n">hy</span> <span class="o">+</span> <span class="n">dy</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span> <span class="o">%</span> <span class="p">(</span><span class="n">H</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="mi">2</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">head</span> <span class="ow">in</span> <span class="n">snake</span><span class="p">:</span>
            <span class="k">break</span>

        <span class="n">snake</span><span class="p">.</span><span class="nf">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">head</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">head</span> <span class="o">==</span> <span class="n">food</span><span class="p">:</span>
            <span class="n">score</span> <span class="o">+=</span> <span class="mi">1</span>
            <span class="n">food</span> <span class="o">=</span> <span class="p">(</span><span class="n">random</span><span class="p">.</span><span class="nf">randint</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">W</span><span class="p">),</span> <span class="n">random</span><span class="p">.</span><span class="nf">randint</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">H</span><span class="p">))</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">tail</span> <span class="o">=</span> <span class="n">snake</span><span class="p">.</span><span class="nf">pop</span><span class="p">()</span>
            <span class="n">sys</span><span class="p">.</span><span class="n">stdout</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="nf">move</span><span class="p">(</span><span class="n">tail</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">tail</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="sh">'</span><span class="s"> </span><span class="sh">'</span><span class="p">)</span>

        <span class="nf">draw</span><span class="p">(</span><span class="n">snake</span><span class="p">,</span> <span class="n">food</span><span class="p">,</span> <span class="n">score</span><span class="p">)</span>
        <span class="n">time</span><span class="p">.</span><span class="nf">sleep</span><span class="p">(</span><span class="nf">max</span><span class="p">(</span><span class="mf">0.04</span><span class="p">,</span> <span class="mf">0.12</span> <span class="o">-</span> <span class="n">score</span> <span class="o">*</span> <span class="mf">0.003</span><span class="p">))</span>
<span class="k">finally</span><span class="p">:</span>
    <span class="n">termios</span><span class="p">.</span><span class="nf">tcsetattr</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">stdin</span><span class="p">,</span> <span class="n">termios</span><span class="p">.</span><span class="n">TCSADRAIN</span><span class="p">,</span> <span class="n">old</span><span class="p">)</span>
    <span class="n">sys</span><span class="p">.</span><span class="n">stdout</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="n">ESC</span> <span class="o">+</span> <span class="sh">'</span><span class="s">?25h</span><span class="sh">'</span> <span class="o">+</span> <span class="n">ESC</span> <span class="o">+</span> <span class="sh">'</span><span class="s">0m</span><span class="sh">'</span> <span class="o">+</span> <span class="sh">'</span><span class="se">\n</span><span class="sh">'</span><span class="p">)</span>
</code></pre></div></div>

<p>Kodda önemli bir performans hilesi var: Her karede tüm ekranı temizlemek yerine sadece değişen hücreleri çiziyoruz. Kuyruğun eski konumuna boşluk basılıyor, yeni baş koordinatına sembol yazılıyor. Bu yaklaşım titremeyi azaltır. Eğer her karede <code class="language-plaintext highlighter-rouge">\x1b[2J</code> kullanırsan oyun çalışır ama göz kırpan bir disko topuna dönüşebilir.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tüm ekranı temizle</td>
      <td>Kod basit</td>
      <td>Titreme fazladır</td>
    </tr>
    <tr>
      <td>Sadece değişeni çiz</td>
      <td>Akıcı görüntü</td>
      <td>Durum takibi gerekir</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">curses</code> kullan</td>
      <td>Hazır araçlar</td>
      <td>ANSI mantığı daha gizli kalır</td>
    </tr>
    <tr>
      <td>Saf ANSI</td>
      <td>Öğretici ve hafif</td>
      <td>Platform farklarına dikkat ister</td>
    </tr>
  </tbody>
</table>

<p>Renk geçişleri için skora göre ANSI renkleri değiştirebilirsin. Örneğin düşük skorda yeşil, orta skorda sarı, yüksek skorda mor yılan kullanmak mümkündür. Hatta RGB destekleyen terminallerde <code class="language-plaintext highlighter-rouge">\x1b[38;2;R;G;Bm</code> biçimiyle gerçek renkler kullanılabilir. Böylece $renk=f(skor)$ gibi küçük bir fonksiyonla oyuna görsel ilerleme hissi katarsın.</p>

<p>Sonuç olarak terminalde yılan oyunu yapmak, oyun programlamanın minyatür laboratuvarı gibidir: koordinat sistemi, olay okuma, zamanlama, çarpışma kontrolü ve render mantığı tek dosyada buluşur. Üstelik tüm bunları grafik kütüphanesi olmadan, yalnızca metin ve birkaç kaçış koduyla yapmak oldukça tatmin edici. Bir sonraki adım olarak duvarlar, seviye sistemi veya renkli parçacık efektleri ekleyebilirsin; terminal sandığından daha canlı bir sahne!</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="ANSI" /><category term="terminal" /><category term="python" /><category term="oyun-programlama" /><category term="kaçış-kodları" /><summary type="html"><![CDATA[Terminali sadece komut yazılan siyah bir kutu sanıyorsan, bugün biraz sihir yapıyoruz: ANSI kaçış kodlarıyla imleci piksel gibi oynatıp, renkleri değiştirip, gerçek zamanlı bir yılan oyunu tasarlayacağız. Buradaki amaç yalnızca “Snake yaptık” demek değil; terminalin nasıl çizim alanına dönüştüğünü, klavye girişinin nasıl anlık okunduğunu ve oyun döngüsünün nasıl çalıştığını anlamak.]]></summary></entry><entry><title type="html">tmpfs ile RAM’de Yaşayan, Kapanınca Unutan Mini Linux</title><link href="https://sonsuzus.github.io/posts/tmpfs-ile-ramde-yasayan-kapaninca-unutan-mini-linux/" rel="alternate" type="text/html" title="tmpfs ile RAM’de Yaşayan, Kapanınca Unutan Mini Linux" /><published>2026-07-22T00:00:00+00:00</published><updated>2026-07-22T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/tmpfs-ile-ramde-yasayan-kapaninca-unutan-mini-linux</id><content type="html" xml:base="https://sonsuzus.github.io/posts/tmpfs-ile-ramde-yasayan-kapaninca-unutan-mini-linux/"><![CDATA[<p>Bilgisayarınız her açılışta tertemiz başlasın, hiçbir iz bırakmasın ve disk yerine RAM hızında çalışsın ister miydiniz? Bu yazıda tmpfs üzerinde bir ramdisk oluşturup, içine minimal bir Linux kök dosya sistemi yerleştirerek tamamen RAM’de çalışan ve güç kesilince sıfırlanan bir sistemin mantığını kuracağız. Bunu bir “kullan-at işletim sistemi” gibi düşünebilirsiniz: hızlı, geçici ve eğlenceli derecede deneysel.
``
Önce temel fikri netleştirelim. <code class="language-plaintext highlighter-rouge">tmpfs</code>, Linux çekirdeğinin RAM ve gerektiğinde swap alanını kullanarak oluşturduğu geçici bir dosya sistemidir. Normal disk bölümü gibi bağlanır, ama veriler kalıcı değildir. Güç kesildiğinde RAM içeriği kaybolduğu için sistem de fabrika ayarına döner. Matematiksel olarak tmpfs için ayırdığımız güvenli alanı kabaca şöyle düşünebiliriz: $S_{tmpfs} = min(RAM - sistem_ihtiyaci, limit)$. Yani 8 GB RAM’iniz varsa 2 GB’lık bir rootfs mantıklı olabilir; 7 GB ayırırsanız çekirdeğin “bana da yer bırakın” deme ihtimali artar.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th style="text-align: right">Hız</th>
      <th style="text-align: right">Kalıcılık</th>
      <th>Kullanım Alanı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Disk üzerindeki Linux</td>
      <td style="text-align: right">Orta/Yüksek</td>
      <td style="text-align: right">Var</td>
      <td>Günlük kullanım</td>
    </tr>
    <tr>
      <td>Live ISO</td>
      <td style="text-align: right">Orta</td>
      <td style="text-align: right">Genelde yok</td>
      <td>Kurtarma, test</td>
    </tr>
    <tr>
      <td>tmpfs RAM Linux</td>
      <td style="text-align: right">Çok yüksek</td>
      <td style="text-align: right">Yok</td>
      <td>Kiosk, güvenli oturum, laboratuvar</td>
    </tr>
  </tbody>
</table>

<p>Bu proje için Alpine Linux güzel bir adaydır; çünkü küçüktür, hızlı kurulur ve minimal sistemlere yakışır. Fakat mantık Debian <code class="language-plaintext highlighter-rouge">debootstrap</code>, BusyBox veya kendi initramfs’inizle de aynıdır: çekirdek başlar, initramfs devreye girer, RAM’de bir kök dosya sistemi hazırlanır ve sistem <code class="language-plaintext highlighter-rouge">switch_root</code> ile oraya geçer.</p>

<p>İlk adımda mevcut çalışan bir Linux üzerinde RAM kök alanı oluşturalım. Bu aşama sistemi gerçekten boot ettirmez; sadece rootfs hazırlama laboratuvarıdır:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo mkdir</span> <span class="nt">-p</span> /mnt/ramroot
<span class="nb">sudo </span>mount <span class="nt">-t</span> tmpfs <span class="nt">-o</span> <span class="nv">size</span><span class="o">=</span>2G,mode<span class="o">=</span>0755 tmpfs /mnt/ramroot
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">size=2G</code>, tmpfs’in üst sınırıdır. Bu, RAM’in anında 2 GB’ının dolduğu anlamına gelmez; tmpfs kullandıkça büyür. Şimdi Alpine mini rootfs arşivini indirip buraya açabiliriz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> /mnt/ramroot
<span class="nb">sudo </span>wget https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/x86_64/alpine-minirootfs-latest-x86_64.tar.gz
<span class="nb">sudo tar </span>xzf alpine-minirootfs-latest-x86_64.tar.gz
<span class="nb">sudo rm </span>alpine-minirootfs-latest-x86_64.tar.gz
</code></pre></div></div>

<p>Bu noktada <code class="language-plaintext highlighter-rouge">/mnt/ramroot</code> içinde küçük ama gerçek bir Linux kullanıcı alanı vardır. DNS, proc, sys ve dev bağlamalarını ekleyip içine chroot ile girebiliriz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>mount <span class="nt">-t</span> proc proc /mnt/ramroot/proc
<span class="nb">sudo </span>mount <span class="nt">--rbind</span> /sys /mnt/ramroot/sys
<span class="nb">sudo </span>mount <span class="nt">--rbind</span> /dev /mnt/ramroot/dev
<span class="nb">sudo cp</span> /etc/resolv.conf /mnt/ramroot/etc/resolv.conf
<span class="nb">sudo chroot</span> /mnt/ramroot /bin/sh
</code></pre></div></div>

<p>Chroot içindeyken temel paketleri ekleyebiliriz. Ama unutmayın: şu an RAM’e yazıyoruz. Kapanınca her şey puf!</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apk update
apk add busybox-openrc openssh vim curl
passwd
</code></pre></div></div>

<p>Asıl sihir boot tarafındadır. Bilgisayar açılırken diskten sadece çekirdek ve initramfs okunur. initramfs içindeki küçük <code class="language-plaintext highlighter-rouge">init</code> betiği tmpfs’i bağlar, sıkıştırılmış rootfs’i RAM’e açar ve kontrolü oraya devreder. Basitleştirilmiş akış şöyledir:</p>

<table>
  <thead>
    <tr>
      <th>Aşama</th>
      <th>Ne olur?</th>
      <th>Kalıcı mı?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Bootloader</td>
      <td>Kernel ve initramfs yüklenir</td>
      <td>Evet, disk/USB üzerinde</td>
    </tr>
    <tr>
      <td>initramfs</td>
      <td>RAM’de tmpfs oluşturur</td>
      <td>Hayır</td>
    </tr>
    <tr>
      <td>rootfs açma</td>
      <td>Minimal Linux tmpfs’e kopyalanır</td>
      <td>Hayır</td>
    </tr>
    <tr>
      <td>switch_root</td>
      <td>Sistem RAM root’a geçer</td>
      <td>Hayır</td>
    </tr>
  </tbody>
</table>

<p>Örnek bir init mantığı şu şekildedir:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
mount <span class="nt">-t</span> proc proc /proc
mount <span class="nt">-t</span> sysfs sys /sys
mount <span class="nt">-t</span> devtmpfs dev /dev
<span class="nb">mkdir</span> /newroot
mount <span class="nt">-t</span> tmpfs <span class="nt">-o</span> <span class="nv">size</span><span class="o">=</span>2G tmpfs /newroot
<span class="nb">tar</span> <span class="nt">-xzf</span> /rootfs.tar.gz <span class="nt">-C</span> /newroot
<span class="nb">exec </span>switch_root /newroot /sbin/init
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">/rootfs.tar.gz</code>, initramfs içine gömülmüş minimal sistem arşividir. Daha üretilebilir bir yapı için rootfs’i SquashFS olarak saklayıp açılışta tmpfs’e kopyalayabilirsiniz. SquashFS daha az yer kaplar; tar.gz ise basitliğiyle kazanır.</p>

<p>Bu mimarinin en güzel yanı güvenlik ve tekrarlanabilirliktir. Bir eğitim laboratuvarında öğrenciler sistemi bozabilir, zararlı yazılım bulaşabilir veya konfigürasyon darmadağın olabilir. Yeniden başlatınca her şey başlangıç haline döner. Dezavantajı ise doğal olarak kalıcılığın olmamasıdır. Log, ayar veya dosya saklamak istiyorsanız ayrı bir kalıcı bölüm bağlamanız gerekir.</p>

<p>Sonuç olarak tmpfs tabanlı RAM Linux; çekirdek, initramfs ve minimal rootfs üçlüsünün dansıdır. Disk sadece kıvılcımı çakar, asıl parti RAM’de döner. Doğru boyutlandırma, küçük dağıtım seçimi ve sade init betiğiyle açılışta doğan, kapanışta hafızalardan silinen sevimli bir işletim sistemi elde edebilirsiniz.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="tmpfs" /><category term="ramdisk" /><category term="linux" /><category term="initramfs" /><category term="alpine" /><summary type="html"><![CDATA[Bilgisayarınız her açılışta tertemiz başlasın, hiçbir iz bırakmasın ve disk yerine RAM hızında çalışsın ister miydiniz? Bu yazıda tmpfs üzerinde bir ramdisk oluşturup, içine minimal bir Linux kök dosya sistemi yerleştirerek tamamen RAM’de çalışan ve güç kesilince sıfırlanan bir sistemin mantığını kuracağız. Bunu bir “kullan-at işletim sistemi” gibi düşünebilirsiniz: hızlı, geçici ve eğlenceli derecede deneysel.]]></summary></entry><entry><title type="html">Hexedit ile Ext4/Btrfs İmajından Silinmiş Dosya Kurtarma: Inode Dedektifliği</title><link href="https://sonsuzus.github.io/posts/hexedit-ile-ext4btrfs-imajindan-silinmis-dosya-kurtarma-inode-dedektifligi/" rel="alternate" type="text/html" title="Hexedit ile Ext4/Btrfs İmajından Silinmiş Dosya Kurtarma: Inode Dedektifliği" /><published>2026-07-21T00:00:00+00:00</published><updated>2026-07-21T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/hexedit-ile-ext4btrfs-imajindan-silinmis-dosya-kurtarma-inode-dedektifligi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/hexedit-ile-ext4btrfs-imajindan-silinmis-dosya-kurtarma-inode-dedektifligi/"><![CDATA[<p>Bir dosya silindiğinde çoğu zaman verinin kendisi anında buharlaşmaz; dosya sisteminin “bu alan artık boş” dediği muhasebe kayıtları değişir. İşte ham disk imajını <code class="language-plaintext highlighter-rouge">hexedit</code> ile açıp inode ve blok adreslerini elle okumak, biraz arkeoloji biraz dedektiflik gibidir: kumların altından byte byte hikâye çıkarırız.
``</p>

<blockquote>
  <p>Not: Bu yazı adli analiz ve kendi verinizi kurtarma senaryoları içindir. Gerçek diskte değil, <strong>imaj kopyası</strong> üzerinde çalışın. Yazma işlemi, kurtarılabilir veriyi ezebilir.</p>
</blockquote>

<h2 id="silinme-ne-demek">Silinme Ne Demek?</h2>

<p>Dosya sistemi bir dosyayı genellikle iki parçayla takip eder: <strong>metadata</strong> ve <strong>data</strong>. Metadata; isim, izin, zaman damgası, inode numarası ve verinin hangi bloklarda durduğunu söyler. Data ise dosyanın gerçek içeriğidir.</p>

<p>Basitleştirilmiş denklem şöyle düşünülebilir:</p>

\[\text{Dosya} = \text{İsim Kaydı} + \text{Inode} + \text{Veri Blokları}\]

<p>Silme sırasında dizin girdisi kaldırılır, inode’un bağlantı sayısı düşer ve bloklar “boş” kabul edilir. Ama bloklar üzerine yeni veri yazılmadıysa hâlâ oradadır.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Ext4</th>
      <th>Btrfs</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Metadata modeli</td>
      <td>Inode tablosu ve blok grupları</td>
      <td>B-tree tabanlı, COW mimarisi</td>
    </tr>
    <tr>
      <td>Elle yorumlama</td>
      <td>Daha öngörülebilir</td>
      <td>Daha karmaşık</td>
    </tr>
    <tr>
      <td>Silinmiş veri şansı</td>
      <td>Üzerine yazılmadıysa iyi</td>
      <td>Snapshot/COW varsa bazen çok iyi</td>
    </tr>
    <tr>
      <td>Zorluk seviyesi</td>
      <td>Orta</td>
      <td>İleri</td>
    </tr>
  </tbody>
</table>

<p>Bu yazıda ana örneği Ext4 üzerinden kuracağız; Btrfs için de mantığı karşılaştıracağız.</p>

<h2 id="güvenli-laboratuvar-hazırlığı">Güvenli Laboratuvar Hazırlığı</h2>

<p>Önce diskten ya da bölümden imaj alın:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo dd </span><span class="k">if</span><span class="o">=</span>/dev/sdb1 <span class="nv">of</span><span class="o">=</span>disk.img <span class="nv">bs</span><span class="o">=</span>4M <span class="nv">status</span><span class="o">=</span>progress <span class="nv">conv</span><span class="o">=</span>noerror,sync
<span class="nb">cp </span>disk.img lab.img
hexedit lab.img
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">hexedit</code> içinde gezinirken unutmayın: sayılar çoğu zaman <strong>little-endian</strong> saklanır. Yani ekranda <code class="language-plaintext highlighter-rouge">00 10 00 00</code> görüyorsanız bu değer <code class="language-plaintext highlighter-rouge">0x00001000</code>, yani 4096 olabilir.</p>

<h2 id="ext4-inode-adresini-hesaplamak">Ext4 Inode Adresini Hesaplamak</h2>

<p>Ext4’te süperblok genelde bölüm başlangıcından 1024 byte sonra başlar. Buradan blok boyutu, inode boyutu, grup başına inode sayısı gibi bilgiler okunur.</p>

<p>Blok boyutu formülü:</p>

\[\text{block\_size} = 1024 \times 2^{s\_log\_block\_size}\]

<p>Bir inode’un disk üzerindeki konumu için:</p>

\[\text{group} = \left\lfloor \frac{inode - 1}{inodes\_per\_group} \right\rfloor\]

\[\text{index} = (inode - 1) \bmod inodes\_per\_group\]

\[\text{inode\_offset} = inode\_table\_block \times block\_size + index \times inode\_size\]

<p>Örneğin inode numarası 131083, blok boyutu 4096, inode boyutu 256 ve grup başına inode sayısı 8192 ise ilgili blok grubunu ve inode tablosundaki yerini bu formüllerle buluruz.</p>

<h2 id="inode-i̇çindeki-i̇puçları">Inode İçindeki İpuçları</h2>

<p>Ext4 inode yapısında önemli alanlar şunlardır:</p>

<table>
  <thead>
    <tr>
      <th>Alan</th>
      <th style="text-align: right">Tipik offset</th>
      <th>Anlamı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">i_mode</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">0x00</code></td>
      <td>Dosya türü ve izinler</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">i_size_lo</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">0x04</code></td>
      <td>Dosya boyutu düşük 32 bit</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">i_links_count</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">0x1A</code></td>
      <td>Bağlantı sayısı</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">i_blocks_lo</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">0x1C</code></td>
      <td>Ayrılmış blok bilgisi</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">i_block</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">0x28</code></td>
      <td>Extent veya blok işaretçileri</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">i_dtime</code></td>
      <td style="text-align: right"><code class="language-plaintext highlighter-rouge">0x14</code></td>
      <td>Silinme zamanı</td>
    </tr>
  </tbody>
</table>

<p>Silinmiş dosyada <code class="language-plaintext highlighter-rouge">i_links_count</code> sıfır olabilir ve <code class="language-plaintext highlighter-rouge">i_dtime</code> doludur. Asıl hazine ise <code class="language-plaintext highlighter-rouge">i_block</code> alanındadır. Modern Ext4 çoğunlukla extent kullanır. <code class="language-plaintext highlighter-rouge">i_block</code> alanında <code class="language-plaintext highlighter-rouge">0a f3</code> görürseniz, bu little-endian <code class="language-plaintext highlighter-rouge">0xf30a</code> extent sihirli değeridir.</p>

<p>Extent başlığı kabaca şöyledir:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>struct ext4_extent_header {
  __le16 eh_magic;    // 0xf30a
  __le16 eh_entries;  // kaç kayıt var
  __le16 eh_max;
  __le16 eh_depth;    // 0 ise yaprak
  __le32 eh_generation;
}
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">eh_depth = 0</code> ise hemen ardından gerçek extent kayıtları gelir:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>struct ext4_extent {
  __le32 ee_block;     // dosya içi mantıksal blok
  __le16 ee_len;       // uzunluk
  __le16 ee_start_hi;  // fiziksel blok üst bitler
  __le32 ee_start_lo;  // fiziksel blok alt bitler
}
</code></pre></div></div>

<p>Fiziksel blok hesabı:</p>

\[\text{physical} = (ee\_start\_hi \ll 32) + ee\_start\_lo\]

<p>Byte offset ise:</p>

\[\text{byte\_offset} = \text{physical} \times \text{block\_size}\]

<h2 id="veriyi-çekmek">Veriyi Çekmek</h2>

<p>Diyelim extent bize fiziksel blok <code class="language-plaintext highlighter-rouge">250000</code>, uzunluk <code class="language-plaintext highlighter-rouge">12</code>, blok boyutu <code class="language-plaintext highlighter-rouge">4096</code> dedi. Dosyayı şöyle çıkarabiliriz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">dd </span><span class="k">if</span><span class="o">=</span>lab.img <span class="nv">of</span><span class="o">=</span>recovered.bin <span class="nv">bs</span><span class="o">=</span>4096 <span class="nv">skip</span><span class="o">=</span>250000 <span class="nv">count</span><span class="o">=</span>12 <span class="nv">status</span><span class="o">=</span>progress
</code></pre></div></div>

<p>Bu komut imajdan 12 blok okur ve <code class="language-plaintext highlighter-rouge">recovered.bin</code> dosyasına yazar. Dosya parçalıysa her extent ayrı çıkarılır, sonra mantıksal blok sırasına göre birleştirilir.</p>

<h2 id="btrfs-neden-daha-çetrefilli">Btrfs Neden Daha Çetrefilli?</h2>

<p>Btrfs’te klasik “inode tablosu” beklentisi boşa düşer. Metadata B-tree yapılarında tutulur; ayrıca Copy-on-Write sayesinde eski sürümlerin izleri kalabilir. Bu harika bir kurtarma şansı sunar ama elle hex ile çözümlemek Ext4’e göre daha zahmetlidir.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Ext4 karşılığı</th>
      <th>Btrfs karşılığı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Inode yeri</td>
      <td>Hesaplanabilir tablo</td>
      <td>B-tree item</td>
    </tr>
    <tr>
      <td>Veri adresi</td>
      <td>Extent alanı</td>
      <td>File extent item</td>
    </tr>
    <tr>
      <td>Eski veri</td>
      <td>Üzerine yazılmadıysa</td>
      <td>COW/snapshot ile kalabilir</td>
    </tr>
    <tr>
      <td>Elle kurtarma</td>
      <td>Formülle mümkün</td>
      <td>Ağaç yapısı takibi gerekir</td>
    </tr>
  </tbody>
</table>

<h2 id="sonuç">Sonuç</h2>

<p>Ext4’te manuel kurtarma; süperbloktan parametreleri okumak, inode adresini hesaplamak, extent kayıtlarını yorumlamak ve fiziksel blokları <code class="language-plaintext highlighter-rouge">dd</code> ile çekmekten ibarettir. Btrfs ise daha modern ve güçlüdür ama elle analizde daha fazla ağaç gezmeyi gerektirir. Kısacası: Ext4 düz bir harita, Btrfs ise üç boyutlu labirenttir. İkisi de çözülebilir; yeter ki byte’lar hâlâ yerinde olsun.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="ext4" /><category term="btrfs" /><category term="forensics" /><category term="hexedit" /><category term="inode" /><summary type="html"><![CDATA[Bir dosya silindiğinde çoğu zaman verinin kendisi anında buharlaşmaz; dosya sisteminin “bu alan artık boş” dediği muhasebe kayıtları değişir. İşte ham disk imajını hexedit ile açıp inode ve blok adreslerini elle okumak, biraz arkeoloji biraz dedektiflik gibidir: kumların altından byte byte hikâye çıkarırız.]]></summary></entry><entry><title type="html">Kabuk Betikleriyle Mini Konteyner Motoru: Namespace ve Cgroup Atölyesi</title><link href="https://sonsuzus.github.io/posts/kabuk-betikleriyle-mini-konteyner-motoru-namespace-ve-cgroup-atolyesi/" rel="alternate" type="text/html" title="Kabuk Betikleriyle Mini Konteyner Motoru: Namespace ve Cgroup Atölyesi" /><published>2026-07-21T00:00:00+00:00</published><updated>2026-07-21T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/kabuk-betikleriyle-mini-konteyner-motoru-namespace-ve-cgroup-atolyesi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/kabuk-betikleriyle-mini-konteyner-motoru-namespace-ve-cgroup-atolyesi/"><![CDATA[<p>Konteyner denince akla hemen Docker gelir; ama sahnenin arkasında sihirli bir ejderha değil, Linux çekirdeğinin çok ciddi iki mekanizması çalışır: ad alanları ve kontrol grupları. Bu yazıda hazır bir konteyner motoru kullanmadan, kabuk betikleriyle küçük ama öğretici bir motor kuracağız. Amaç üretim ortamına rakip çıkarmak değil; kaputun altındaki pistonları tek tek görmek.
``</p>

<p>Önce teoriyi netleştirelim. Linux namespace, bir sürece gerçek sistemin yalnızca belirli bir görünümünü verir. Yani süreç kendini ayrı bir makinedeymiş gibi hisseder. Cgroup ise o sürecin ne kadar CPU, bellek veya süreç sayısı kullanabileceğini sınırlar. Basit denklemle: konteyner hissi = izolasyon + kaynak limiti + ayrı dosya sistemi. Bunu şöyle yazabiliriz: $K = N + C + R$, burada $N$ namespace, $C$ cgroup, $R$ rootfs anlamına gelir.</p>

<table>
  <thead>
    <tr>
      <th>Mekanizma</th>
      <th>Ne yapar?</th>
      <th>Günlük benzetme</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>PID namespace</td>
      <td>Süreç numaralarını izole eder</td>
      <td>Her sınıfta ayrı yoklama listesi</td>
    </tr>
    <tr>
      <td>Mount namespace</td>
      <td>Bağlama noktalarını ayırır</td>
      <td>Her odanın kendi raf düzeni</td>
    </tr>
    <tr>
      <td>UTS namespace</td>
      <td>Hostname bilgisini ayırır</td>
      <td>Her evin farklı kapı tabelası</td>
    </tr>
    <tr>
      <td>Network namespace</td>
      <td>Ağ arayüzlerini ayırır</td>
      <td>Ayrı mahalle yolları</td>
    </tr>
    <tr>
      <td>Cgroup v2</td>
      <td>Kaynak tüketimini sınırlar</td>
      <td>Elektrik, su, internet kotası</td>
    </tr>
  </tbody>
</table>

<p>Bir konteynerin kök dosya sistemine ihtiyacı vardır. Debian tabanlı küçük bir rootfs hazırlamak için örnek:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>debootstrap <span class="nt">--variant</span><span class="o">=</span>minbase bookworm ./rootfs http://deb.debian.org/debian
<span class="nb">sudo mkdir</span> <span class="nt">-p</span> ./rootfs/<span class="o">{</span>proc,sys,tmp<span class="o">}</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">rootfs</code>, konteynerin kendi dünyasıdır. <code class="language-plaintext highlighter-rouge">chroot</code> ile bir sürecin kök dizinini buraya çevirebiliriz; fakat tek başına <code class="language-plaintext highlighter-rouge">chroot</code> güvenlik sınırı değildir. Asıl izolasyonu <code class="language-plaintext highlighter-rouge">unshare</code> komutu ile namespace oluşturarak sağlarız.</p>

<p>Şimdi küçük motorumuzun iskeletini yazalım:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> <span class="o">&gt;</span> mini-run.sh <span class="o">&lt;&lt;</span><span class="sh">'</span><span class="no">SH</span><span class="sh">'
#!/usr/bin/env bash
set -euo pipefail

ROOTFS=</span><span class="k">${</span><span class="nv">ROOTFS</span><span class="k">:-</span><span class="p">./rootfs</span><span class="k">}</span><span class="sh">
ID=</span><span class="k">${</span><span class="nv">1</span><span class="k">:-</span><span class="nv">demo</span><span class="k">}</span><span class="sh">
CG=/sys/fs/cgroup/mini-</span><span class="nv">$ID</span><span class="sh">

mkdir -p </span><span class="nv">$CG</span><span class="sh">
echo +cpu +memory +pids &gt; /sys/fs/cgroup/cgroup.subtree_control 2&gt;/dev/null || true
echo '50000 100000' &gt; </span><span class="nv">$CG</span><span class="sh">/cpu.max
echo </span><span class="k">$((</span><span class="m">128</span><span class="o">*</span><span class="m">1024</span><span class="o">*</span><span class="m">1024</span><span class="k">))</span><span class="sh"> &gt; </span><span class="nv">$CG</span><span class="sh">/memory.max
echo 64 &gt; </span><span class="nv">$CG</span><span class="sh">/pids.max

unshare --fork --pid --mount --uts --ipc --net --mount-proc </span><span class="se">\</span><span class="sh">
  chroot </span><span class="nv">$ROOTFS</span><span class="sh"> /bin/bash -lc 'hostname mini; mount -t proc proc /proc; exec /bin/bash' &amp;

CHILD=</span><span class="nv">$!</span><span class="sh">
echo </span><span class="nv">$CHILD</span><span class="sh"> &gt; </span><span class="nv">$CG</span><span class="sh">/cgroup.procs
wait </span><span class="nv">$CHILD</span><span class="sh">
rm -rf </span><span class="nv">$CG</span><span class="sh">
</span><span class="no">SH

</span><span class="nb">chmod</span> +x mini-run.sh
<span class="nb">sudo</span> ./mini-run.sh ilk-konteyner
</code></pre></div></div>

<p>Bu betik birkaç kritik şey yapar. Önce cgroup dizini açar, sonra CPU, bellek ve süreç sayısı sınırı koyar. <code class="language-plaintext highlighter-rouge">cpu.max</code> satırındaki <code class="language-plaintext highlighter-rouge">50000 100000</code>, her 100000 mikrosaniyelik periyotta 50000 mikrosaniye CPU hakkı demektir. Yani $oran = 50000 / 100000 = 0.5$; kabaca yarım CPU çekirdeği. Bellek sınırı ise $128 * 1024 * 1024$ bayt, yani 128 MB olur.</p>

<p><code class="language-plaintext highlighter-rouge">unshare</code> tarafı daha eğlenceli. <code class="language-plaintext highlighter-rouge">--pid</code> ile içerideki kabuk kendini yeni bir süreç ağacında görür. <code class="language-plaintext highlighter-rouge">--mount</code> sayesinde mount değişiklikleri dışarı sızmaz. <code class="language-plaintext highlighter-rouge">--uts</code> hostname değiştirmeye izin verir. <code class="language-plaintext highlighter-rouge">--net</code> yeni ve boş bir ağ namespace açar; bu yüzden konteyner ilk anda internetsizdir. Gerçek motorlar burada veth çifti, bridge ve NAT kurar.</p>

<table>
  <thead>
    <tr>
      <th>Eksik parça</th>
      <th>Bizde durum</th>
      <th>Docker gibi motorlarda</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Image katmanları</td>
      <td>Yok, tek rootfs</td>
      <td>OverlayFS katmanları</td>
    </tr>
    <tr>
      <td>Ağ</td>
      <td>Boş namespace</td>
      <td>Bridge, veth, iptables veya nftables</td>
    </tr>
    <tr>
      <td>Güvenlik</td>
      <td>Temel izolasyon</td>
      <td>Seccomp, AppArmor, capability azaltma</td>
    </tr>
    <tr>
      <td>Yaşam döngüsü</td>
      <td>Basit wait</td>
      <td>start, stop, logs, exec</td>
    </tr>
  </tbody>
</table>

<p>Ağ eklemek istersen fikir şudur: host tarafında bir bridge oluşturulur, konteyner namespace içine bir veth ucu taşınır, IP verilir ve NAT açılır. Bunu elle yapmak öğreticidir ama dağıtıma göre komutlar değişebilir.</p>

<p>Önemli uyarı: Bu betiği root yetkisiyle çalıştırırsın ve bu bir öğrenme aracıdır. Güvenli konteyner motoru yazmak; capability düşürme, salt okunur mount, kullanıcı namespace, seccomp profili ve dikkatli cleanup gerektirir.</p>

<p>Sonuç olarak konteyner, gizemli bir kutu değil; iyi düzenlenmiş bir Linux illüzyonudur. Namespace sürece ayrı bir evren gösterir, cgroup o evrende ne kadar kaynak yakabileceğini belirler, rootfs ise dekoru tamamlar. Docker veya Podman kullandığında artık sadece komut çalıştırmış olmayacaksın; çekirdeğin hangi düğmelerine basıldığını da zihninde göreceksin.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="linux" /><category term="container" /><category term="bash" /><category term="namespace" /><category term="cgroup" /><summary type="html"><![CDATA[Konteyner denince akla hemen Docker gelir; ama sahnenin arkasında sihirli bir ejderha değil, Linux çekirdeğinin çok ciddi iki mekanizması çalışır: ad alanları ve kontrol grupları. Bu yazıda hazır bir konteyner motoru kullanmadan, kabuk betikleriyle küçük ama öğretici bir motor kuracağız. Amaç üretim ortamına rakip çıkarmak değil; kaputun altındaki pistonları tek tek görmek.]]></summary></entry></feed>