<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Red on inetshell</title><link>https://inet.sh/es/posts/network/</link><description>Recent content in Red on inetshell</description><generator>Hugo</generator><language>es</language><lastBuildDate>Sat, 26 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://inet.sh/es/posts/network/index.xml" rel="self" type="application/rss+xml"/><item><title>DHCP opción 121: rutas estáticas classless (RFC 3442), cómo codificarlas en hex y ponerlas en ISC dhcpd, Kea, pfSense y MikroTik</title><link>https://inet.sh/es/posts/network/dhcp-opcion-121-rutas-estaticas-classless/</link><pubDate>Sat, 26 Sep 2026 00:00:00 +0000</pubDate><guid>https://inet.sh/es/posts/network/dhcp-opcion-121-rutas-estaticas-classless/</guid><description>Para que los clientes DHCP lleguen a otra red por un router distinto del gateway (una VPN site-to-site, un segundo enlace) sin tocar cada equipo, el servidor DHCP entrega rutas con la opción 121. El formato es binario: un octeto con la longitud del prefijo, solo los octetos significativos del destino y los cuatro del router, todo concatenado. Un script Python que lo genera en los cuatro formatos que piden ISC dhcpd, Kea, pfSense y MikroTik, y la regla que rompe la red si la olvidas: si mandas la 121, el cliente ignora la opción 3 y tienes que incluir la ruta por defecto.</description><content:encoded><![CDATA[<h2 id="en-corto">En corto</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="ch">#!/usr/bin/env python3</span>
</span></span><span class="line"><span class="cl"><span class="s2">&#34;&#34;&#34;Codifica rutas classless (RFC 3442) para la opción DHCP 121.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">ipaddress</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">encode</span><span class="p">(</span><span class="n">routes</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">out</span> <span class="o">=</span> <span class="nb">bytearray</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">dest</span><span class="p">,</span> <span class="n">via</span> <span class="ow">in</span> <span class="n">routes</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">net</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="n">dest</span><span class="p">,</span> <span class="n">strict</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">n</span> <span class="o">=</span> <span class="p">(</span><span class="n">net</span><span class="o">.</span><span class="n">prefixlen</span> <span class="o">+</span> <span class="mi">7</span><span class="p">)</span> <span class="o">//</span> <span class="mi">8</span>                 <span class="c1"># octetos significativos del destino</span>
</span></span><span class="line"><span class="cl">        <span class="n">out</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">net</span><span class="o">.</span><span class="n">prefixlen</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">out</span> <span class="o">+=</span> <span class="n">net</span><span class="o">.</span><span class="n">network_address</span><span class="o">.</span><span class="n">packed</span><span class="p">[:</span><span class="n">n</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">out</span> <span class="o">+=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="n">via</span><span class="p">)</span><span class="o">.</span><span class="n">packed</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">out</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">routes</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;192.0.2.0/24&#34;</span><span class="p">,</span> <span class="s2">&#34;192.168.1.254&#34;</span><span class="p">),</span>   <span class="c1"># la otra sede, por el router de la VPN</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;0.0.0.0/0&#34;</span><span class="p">,</span>    <span class="s2">&#34;192.168.1.1&#34;</span><span class="p">),</span>     <span class="c1"># la ruta por defecto: obligatoria si mandas la 121</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">raw</span> <span class="o">=</span> <span class="n">encode</span><span class="p">(</span><span class="n">routes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;hex      &#34;</span><span class="p">,</span> <span class="n">raw</span><span class="o">.</span><span class="n">hex</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;mikrotik &#34;</span><span class="p">,</span> <span class="s2">&#34;0x&#34;</span> <span class="o">+</span> <span class="n">raw</span><span class="o">.</span><span class="n">hex</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;isc      &#34;</span><span class="p">,</span> <span class="s2">&#34;, &#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">raw</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;pfsense  &#34;</span><span class="p">,</span> <span class="s2">&#34;:&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">b</span><span class="si">:</span><span class="s2">02x</span><span class="si">}</span><span class="s2">&#34;</span> <span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">raw</span><span class="p">))</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">hex       18c00002c0a801fe00c0a80101
</span></span><span class="line"><span class="cl">mikrotik  0x18c00002c0a801fe00c0a80101
</span></span><span class="line"><span class="cl">isc       24, 192, 0, 2, 192, 168, 1, 254, 0, 192, 168, 1, 1
</span></span><span class="line"><span class="cl">pfsense   18:c0:00:02:c0:a8:01:fe:00:c0:a8:01:01
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="el-formato">El formato</h2>
<p>Cada ruta de la opción 121 son tres campos pegados, sin separadores:</p>
<table>
  <thead>
      <tr>
          <th>Campo</th>
          <th>Tamaño</th>
          <th>Ejemplo <code>192.0.2.0/24 via 192.168.1.254</code></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Longitud del prefijo</td>
          <td>1 octeto</td>
          <td><code>18</code> (24)</td>
      </tr>
      <tr>
          <td>Destino, <strong>solo los octetos significativos</strong>: ⌈prefijo / 8⌉</td>
          <td>0 a 4 octetos</td>
          <td><code>c0 00 02</code> (192.0.2)</td>
      </tr>
      <tr>
          <td>Router</td>
          <td>4 octetos</td>
          <td><code>c0 a8 01 fe</code></td>
      </tr>
  </tbody>
</table>
<p>Un <code>/24</code> lleva tres octetos de destino, un <code>/16</code> dos, un <code>/32</code> cuatro, y la ruta por defecto <code>/0</code> <strong>ninguno</strong>: <code>00</code> seguido directamente del router. Varias rutas se concatenan; la opción entera cabe en 255 octetos (unas 28 rutas <code>/24</code>).</p>
<h2 id="la-regla-que-rompe-la-red">La regla que rompe la red</h2>
<p>RFC 3442, sección 3: <em>&ldquo;If the DHCP server returns both a Classless Static Routes option and a Router option, the DHCP client MUST ignore the Router option.&rdquo;</em> Si empiezas a mandar la 121 con una sola ruta a la otra sede, los clientes que la entienden <strong>pierden la puerta de enlace</strong> de la opción 3 y se quedan sin salida a Internet. La ruta por defecto va dentro de la 121, siempre, como en el ejemplo. Los clientes que no entienden la 121 siguen usando la opción 3, así que déjala configurada también.</p>
<h2 id="dónde-se-pone">Dónde se pone</h2>
<p><strong>ISC dhcpd</strong> (<code>dhcpd.conf</code>): hay que declarar la opción, y conviene mandarla también como 249, que es la que piden los Windows antiguos:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
</span></span><span class="line"><span class="cl">option ms-classless-static-routes code 249 = array of unsigned integer 8;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">subnet 192.168.1.0 netmask 255.255.255.0 {
</span></span><span class="line"><span class="cl">  range 192.168.1.100 192.168.1.199;
</span></span><span class="line"><span class="cl">  option routers 192.168.1.1;
</span></span><span class="line"><span class="cl">  option rfc3442-classless-static-routes 24, 192,0,2, 192,168,1,254, 0, 192,168,1,1;
</span></span><span class="line"><span class="cl">  option ms-classless-static-routes     24, 192,0,2, 192,168,1,254, 0, 192,168,1,1;
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>Kea</strong> (2.4 o posterior) entiende la opción por nombre y con notación legible, sin hex:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;option-data&#34;</span><span class="err">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;classless-static-route&#34;</span><span class="p">,</span> <span class="nt">&#34;code&#34;</span><span class="p">:</span> <span class="mi">121</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="s2">&#34;192.0.2.0/24 - 192.168.1.254, 0.0.0.0/0 - 192.168.1.1&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>pfSense / OPNsense</strong>: con el backend ISC, <em>Services → DHCP Server → Additional BOOTP/DHCP Options</em>, número <code>121</code>, tipo <em>String</em>, valor en hex con dos puntos (<code>18:c0:00:02:…</code>); añade otra con <code>249</code> para Windows. Con el backend <strong>Kea</strong>, la opción 121 todavía no está en la interfaz (a fecha de este post hay peticiones abiertas en los dos proyectos); si tu versión permite opciones personalizadas de Kea, usa el JSON de arriba; si no, es el motivo para seguir en ISC.</p>
<p><strong>MikroTik RouterOS</strong>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">/ip dhcp-server option add name=classless code=121 value=0x18c00002c0a801fe00c0a80101
</span></span><span class="line"><span class="cl">/ip dhcp-server option add name=classless-ms code=249 value=0x18c00002c0a801fe00c0a80101
</span></span><span class="line"><span class="cl">/ip dhcp-server option sets add name=routes options=classless,classless-ms
</span></span><span class="line"><span class="cl">/ip dhcp-server network set [find address=192.168.1.0/24] dhcp-option-set=routes
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="qué-clientes-la-entienden">Qué clientes la entienden</h2>
<table>
  <thead>
      <tr>
          <th>Cliente</th>
          <th>Opción 121</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Windows (Vista y posteriores)</td>
          <td>Sí; también acepta la 249</td>
      </tr>
      <tr>
          <td>Linux con NetworkManager o systemd-networkd</td>
          <td>Sí, sin configurar nada</td>
      </tr>
      <tr>
          <td>Linux con <code>dhclient</code></td>
          <td>Solo si <code>rfc3442-classless-static-routes</code> está en la lista <code>request</code> de <code>dhclient.conf</code> y hay un hook que instale las rutas (Debian y Ubuntu lo traen en <code>/etc/dhcp/dhclient-exit-hooks.d/</code>)</td>
      </tr>
      <tr>
          <td>macOS e iOS</td>
          <td>Sí</td>
      </tr>
      <tr>
          <td>Android</td>
          <td>Históricamente la ignora; no cuentes con ella</td>
      </tr>
      <tr>
          <td>FreeBSD <code>dhclient</code></td>
          <td>No sin <code>dhclient-script</code> a medida; <code>dhcpcd</code> sí</td>
      </tr>
  </tbody>
</table>
<p>Compruébalo en el cliente con <code>ip route</code> (Linux), <code>route print</code> (Windows) o <code>netstat -rn</code> (macOS) tras renovar el lease.</p>
<h2 id="trampas">Trampas</h2>
<ul>
<li><strong><code>/32</code> con router en otra subred</strong>: válido en la codificación, pero el cliente necesita una ruta previa al router; ordena las rutas de más específica a menos y pon primero la del propio segmento si hace falta.</li>
<li><strong>Rutas hacia redes que el DHCP no controla</strong> (un servidor DHCP en una VLAN que anuncia rutas por otra) se aceptan igual: la 121 es una lista de texto, nadie la valida. Un error de un octeto se convierte en una ruta hacia una red inventada.</li>
<li><strong>Los clientes no revisan las rutas hasta renovar</strong> el lease; tras cambiar la opción, <code>T1</code> (la mitad del lease) es lo que tardarán en verla, o fuerza la renovación.</li>
<li><strong>Windows y la 249</strong>: si solo mandas la 121, los Windows modernos la usan; la 249 es por compatibilidad y contiene exactamente los mismos bytes.</li>
<li><strong>Anuncios <code>/0</code> desde un DHCP ajeno</strong>: cualquier servidor DHCP de la LAN puede reescribir la ruta por defecto de todos los clientes con la 121; DHCP snooping en el switch es la única defensa real.</li>
</ul>
<p>Referencia: <a href="https://datatracker.ietf.org/doc/rfc3442/">RFC 3442</a>.</p>
<h2 id="ver-también">Ver también</h2>
<ul>
<li><a href="/es/posts/gcp/cloud-vpn-no-levanta-logs-ike/">Cloud VPN de GCP no levanta</a> — la VPN por la que suelen ir estas rutas.</li>
<li><a href="/es/posts/pfsense/nat-reflection-port-forward-desde-lan/">pfSense: NAT reflection y split DNS</a> — el otro ajuste de LAN que los clientes reciben sin enterarse.</li>
</ul>
]]></content:encoded></item></channel></rss>