<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[It’s done, just needs testing]]></title><description><![CDATA[It’s done, just needs testing]]></description><link>https://blog.maicol.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1730584153984/9acea3a2-9cfb-4cc1-9686-7b1023684f3f.png</url><title>It’s done, just needs testing</title><link>https://blog.maicol.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 17:00:22 GMT</lastBuildDate><atom:link href="https://blog.maicol.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Além do Código: Redes de Computador para Desenvolvedores]]></title><description><![CDATA[Resumo
Hoje em dia, utilizamos amplamente o conceito de containers, o que nos obriga a compreender melhor essa tecnologia. Consequentemente, isso nos leva a adquirir ao menos um conhecimento básico sobre redes. Este artigo será focado no essencial qu...]]></description><link>https://blog.maicol.dev/alem-do-codigo-redes-de-computador-para-desenvolvedores</link><guid isPermaLink="true">https://blog.maicol.dev/alem-do-codigo-redes-de-computador-para-desenvolvedores</guid><category><![CDATA[upnp]]></category><category><![CDATA[ssdp]]></category><category><![CDATA[TCP/IP]]></category><category><![CDATA[docker-network]]></category><category><![CDATA[linux networking ]]></category><category><![CDATA[broadcast]]></category><dc:creator><![CDATA[Maicol Kaiser]]></dc:creator><pubDate>Sat, 18 Jan 2025 03:02:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735562551381/03c7b308-2d6f-4ffa-b7be-ca288eed6834.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<h1 id="heading-resumo">Resumo</h1>
<p>Hoje em dia, utilizamos amplamente o conceito de containers, o que nos obriga a compreender melhor essa tecnologia. Consequentemente, isso nos leva a adquirir ao menos um conhecimento básico sobre redes. Este artigo será focado no essencial que você precisa saber sobre redes para se sentir mais à vontade ao lidar com assuntos relacionados a TCP/IP.</p>
<p>Você vai encontrar os códigos apresentados aqui, no repositorio baixo:</p>
<p>→ <a target="_blank" href="https://github.com/vakaman/Alem-do-Codigo-Redes-de-computador-para-desenvolvedores">https://github.com/vakaman/Alem-do-Codigo-Redes-de-computador-para-desenvolvedores</a></p>
<hr />
<h1 id="heading-por-que-entender-redes-e-essencial-para-o-sucesso-do-seu-codigo">Por que entender redes é essencial para o sucesso do seu código?</h1>
<hr />
<p>Já de antemão e para ser bem sincero, pro seu código em sí, não muda muita coisa não, talvez em algum momento você tenha alguns insites interessantes por já ter visto uma abstração parecida em algum protocolo de rede.</p>
<p>Isso significa que redes não são um problema seu? Não! e eu posso provar.</p>
<p>Hoje vivemos na era dos containers e nos comunicamos com eles frequentemente através de redes TCP/IP, sendo assim… se você quer se manter longe de problemas quando o assunto é redes vem comigo, mas antes… vamos passar pelo básico.</p>
<p>Antes de começar, um ponto que acho interessante reforçar é… se você se sente confortável com o conhecimento de redes que tem hoje e o que eu falei anteriormente reforça a sua ideia de que você já sabe o suficiente, não continue, talvez não faça sentido de fato para você. Agora… se você quer desbravar algo que ainda não teve a oportunidade de ter contato, eu fico feliz e te desejo uma boa leitura.</p>
<h1 id="heading-dominios-de-sub-rede">Domínios de sub-rede</h1>
<p>Imagine um cenário onde um grupo de computadores precisa se comunicar, porém para que isto seja possível, um padrão deve ser definido, uma das regras deste padrão é que cada um que entre neste grupo não possa ter identificadores duplicados. Outra regra importante é que os grupos têm tamanhos fixos e previamente definidos. Com isto em mente vou tentar explicar de uma forma didática o mínimo que você precisa saber para entender o conceito.</p>
<p>Aposto que você já viu algumas destas redes 10.0.0.1/24, 192.168.0.0/24, 172.31.0.0/24, e isto se dá pelo fato de serem redes utilizadas dentro do que chamamos rede local, para os exemplos à seguir vou utiliza o prefixo 192.168.0.0/24, mas o conceito se aplica para todos os prefixos do protocolo IP.</p>
<p>Dentro do prefixo 192.168.0.0/24 temos 255 posições, imagine que cada posição pode ser ocupada por um computador com exceção das reservadas.</p>
<p>Mas… como eu sei que são 255? que define isso? 🤔</p>
<p>A máscara de sub-rede, que neste caso é o /24. Mais um nome estranho né? eu sei…eu sei… calma… vamos por partes. Vamos passar pelos nomes logo abaixo, vai ficar fácil entender, confia.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Host</strong></td><td>pode ser muitas coisas, desde sua televisão ao um contâiner do postgresql</td><td>Um dispositivo ou um serviço. Todos que tem suporte ao protocolo tcp/ip podem ser considerados um host.</td></tr>
</thead>
<tbody>
<tr>
<td><strong>IP</strong></td><td>192.168.0.0 ou 192.168.0.239 ou 1.1.1.1</td><td>Um único endereço, a unidade de fato, o identificador de um host em uma rede.</td></tr>
<tr>
<td><strong>Mascara de sub-rede</strong></td><td>255.255.255.0 ou simplesmente /24</td><td>A definição dos limites, onde termina uma rede.</td></tr>
<tr>
<td><strong>Prefixo ou Rede</strong></td><td>192.168.0.0/24</td><td>A junção do IP com a máscara de sub-rede, define os limites da rede com os dois sabemos onde inicia e onde termina o range dos IP’s daquele domínio.</td></tr>
</tbody>
</table>
</div><p>Quando definimos as fronteiras de uma rede, estamos estabelecendo um grupo onde todos os participantes podem se comunicar de forma direta ou seja</p>
<p>O host com o IP 192.168.0.10/24 pode se comunicar com o host 192.168.10.11/24 se a necessidade de ou terceiro elemento. Caso algum destes host queira se comunicar com o endereço 10.0.0.10 ele precisa passar por um roteador, mas… daí é uma longa história, vou tentar ir pelo caminho mais curto.</p>
<p>Se sabemos que o endereço 192.168.0.0/24 possui 255 ips e alguns são reservados, quais eu não posso usar?</p>
<p><code>NO | 192.168.0.0 → rede ( define o inicio da rede )</code></p>
<p><code>NO | 192.168.0.1 → gateway ( normalmente um roteador, ele conecta a rede local com outras redes)</code></p>
<p><code>YES | 192.168.0.2-254 → livre para alocação ( posições que podemos utilizar )</code></p>
<p><code>NO | 192.168.0.255 → broadcast ( envia mensagens para todos na mesma sub-rede simultaneamente )</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736290837064/bc734db0-fab2-4a95-8bad-4dcc8b32afac.png" alt class="image--center mx-auto" /></p>
<p>Normalmente o que vemos em nossas casas é algo parecido com o desenho acima, onde temos um roteador e diversos hosts, cada um deles contém sua tabela de rotas, onde através dela os hosts sabem qual a rede que eles fazem parte e para quem ele precisa perguntar nos casos onde ele não conhece a rede.</p>
<p>Ok, ok tudo muito bonito e tals, mas… oq isso tem a ver com os containers?</p>
<p>Pois então… os containers fazem parte de uma sub-rede, e eles só conseguem se comunicar se estiverem na mesma rede e com permissão para tal.</p>
<hr />
<h1 id="heading-o-que-e-e-pra-que-servem-as-portas">O que é e pra que servem as portas?</h1>
<p>De forma simplista as portas TCP têm a função de criar um canal de comunicação entre dois hosts. Essa conexão é associada a um processo, mas… se acalme que a gente vai chegar lá e você vai conseguir entender o que isso significa.</p>
<p>Existem 65535 portas TCP disponíveis, entretanto, existe uma organização separando as portas para cada contexto, vamos passar brevemente por esta separação</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>FUNÇÃO</strong></td><td><strong>RANGE</strong></td><td><strong>DETALHE</strong></td></tr>
</thead>
<tbody>
<tr>
<td><a target="_blank" href="https://datatracker.ietf.org/doc/html/rfc1340#page-9">WELL KNOWN PORT</a></td><td>0-1023</td><td>São portas utilizadas por sistemas e ou processos root</td></tr>
<tr>
<td><a target="_blank" href="https://datatracker.ietf.org/doc/html/rfc1340#page-23">REGISTERED PORT</a></td><td>1024-49151</td><td>Portas registradas são usadas no TCP e listadas pela IANA como conveniência, mas não são controladas.</td></tr>
<tr>
<td><a target="_blank" href="https://www.rfc-editor.org/rfc/rfc6335#section-6">PRIVATE OR EPHEMETAL PORTS</a></td><td>49152-65535</td><td>Atribuídas dinamicamente para conexões temporárias</td></tr>
</tbody>
</table>
</div><p>Vamos simular o cenário abaixo, para fazer com que o host A, crie uma conexão com o host B através das portas TCP.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737292199836/02d48fb3-d798-4c42-9a1c-811671d6bfc2.png" alt class="image--center mx-auto" /></p>
<p>Como podemos ver, temos um servidor, que chamamos de host_a_server, ele tem um processo PID 1, escutando na porta 6969.</p>
<p>Já do outro lado, temos um segundo elemento que chamamos de host_b_client, que deverá iniciar uma requisição para o servidor com destino a porta 6969 do servidor e para que a conexão seja estabelecida uma porta de origem é associada a esta conexão.</p>
<p>Servidor</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> socket
<span class="hljs-keyword">import</span> logging

logging.basicConfig(
    level=logging.INFO,
    format=<span class="hljs-string">'%(asctime)s - %(levelname)s - %(message)s'</span>
)

HOST = <span class="hljs-string">'0.0.0.0'</span>
PORT = <span class="hljs-number">6969</span>

logging.info(<span class="hljs-string">"Iniciando servidor..."</span>)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((HOST, PORT))
server_socket.listen(<span class="hljs-number">1</span>)

logging.info(<span class="hljs-string">f"Servidor escutando na porta <span class="hljs-subst">{PORT}</span>..."</span>)

<span class="hljs-keyword">try</span>:
    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
        connection, client_address = server_socket.accept()
        logging.info(<span class="hljs-string">f"Conexão estabelecida com <span class="hljs-subst">{client_address}</span>"</span>)

        data = connection.recv(<span class="hljs-number">1024</span>).decode(<span class="hljs-string">'utf-8'</span>)
        <span class="hljs-keyword">if</span> data:
            logging.info(<span class="hljs-string">f"Mensagem recebida: <span class="hljs-subst">{data}</span>"</span>)
            connection.sendall(
                <span class="hljs-string">"Olá, cliente! Conexão estabelecida."</span>.encode(<span class="hljs-string">'utf-8'</span>)
            )
        connection.close()
        logging.info(<span class="hljs-string">f"Conexão com <span class="hljs-subst">{client_address}</span> encerrada."</span>)
<span class="hljs-keyword">except</span> KeyboardInterrupt:
    logging.info(<span class="hljs-string">"Servidor interrompido manualmente."</span>)
<span class="hljs-keyword">finally</span>:
    server_socket.close()
    logging.info(<span class="hljs-string">"Servidor finalizado."</span>)
</code></pre>
<p>Cliente</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> socket
<span class="hljs-keyword">import</span> logging
<span class="hljs-keyword">import</span> os

logging.basicConfig(
    level=logging.INFO,
    format=<span class="hljs-string">'%(asctime)s - %(levelname)s - %(message)s'</span>
)


HOST = os.getenv(<span class="hljs-string">"SERVER_HOST"</span>, <span class="hljs-string">"host_a_server"</span>)
PORT = <span class="hljs-number">6969</span>

logging.info(<span class="hljs-string">f"Tentando conectar ao servidor <span class="hljs-subst">{HOST}</span>:<span class="hljs-subst">{PORT}</span>..."</span>)
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

<span class="hljs-keyword">try</span>:
    client_socket.connect((HOST, PORT))
    logging.info(<span class="hljs-string">f"Cliente conectado ao servidor <span class="hljs-subst">{HOST}</span>:<span class="hljs-subst">{PORT}</span>"</span>)

    client_socket.sendall(<span class="hljs-string">"Olá, servidor!"</span>.encode(<span class="hljs-string">'utf-8'</span>))
    logging.info(<span class="hljs-string">"Mensagem enviada ao servidor."</span>)

    data = client_socket.recv(<span class="hljs-number">1024</span>).decode(<span class="hljs-string">'utf-8'</span>)
    logging.info(<span class="hljs-string">f"Resposta do servidor: <span class="hljs-subst">{data}</span>"</span>)
<span class="hljs-keyword">finally</span>:
    client_socket.close()
    logging.info(<span class="hljs-string">"Conexão com o servidor encerrada."</span>)
</code></pre>
<p>Assim que rodamos o projeto, vamos ver este comportamento.</p>
<pre><code class="lang-apache"><span class="hljs-attribute">host_a_server</span>  | <span class="hljs-number">2025</span>-<span class="hljs-number">01</span>-<span class="hljs-number">19</span> <span class="hljs-number">13</span>:<span class="hljs-number">05</span>:<span class="hljs-number">16</span>,<span class="hljs-number">795</span> - INFO - Iniciando servidor...
<span class="hljs-attribute">host_a_server</span>  | <span class="hljs-number">2025</span>-<span class="hljs-number">01</span>-<span class="hljs-number">19</span> <span class="hljs-number">13</span>:<span class="hljs-number">05</span>:<span class="hljs-number">16</span>,<span class="hljs-number">795</span> - INFO - Servidor escutando na porta <span class="hljs-number">6969</span>...

<span class="hljs-attribute">host_b_client</span>  | <span class="hljs-number">2025</span>-<span class="hljs-number">01</span>-<span class="hljs-number">19</span> <span class="hljs-number">13</span>:<span class="hljs-number">05</span>:<span class="hljs-number">17</span>,<span class="hljs-number">028</span> - INFO - Tentando conectar ao servidor host_a_server:<span class="hljs-number">6969</span>...
<span class="hljs-attribute">host_b_client</span>  | <span class="hljs-number">2025</span>-<span class="hljs-number">01</span>-<span class="hljs-number">19</span> <span class="hljs-number">13</span>:<span class="hljs-number">05</span>:<span class="hljs-number">17</span>,<span class="hljs-number">029</span> - INFO - Cliente conectado ao servidor host_a_server:<span class="hljs-number">6969</span>
<span class="hljs-attribute">host_b_client</span>  | <span class="hljs-number">2025</span>-<span class="hljs-number">01</span>-<span class="hljs-number">19</span> <span class="hljs-number">13</span>:<span class="hljs-number">05</span>:<span class="hljs-number">17</span>,<span class="hljs-number">029</span> - INFO - Mensagem enviada ao servidor.

<span class="hljs-attribute">host_a_server</span>  | <span class="hljs-number">2025</span>-<span class="hljs-number">01</span>-<span class="hljs-number">19</span> <span class="hljs-number">13</span>:<span class="hljs-number">05</span>:<span class="hljs-number">17</span>,<span class="hljs-number">029</span> - INFO - Conexão estabelecida com ('<span class="hljs-number">1.2.9.3</span>', <span class="hljs-number">44890</span>)

<span class="hljs-attribute">host_b_client</span>  | <span class="hljs-number">2025</span>-<span class="hljs-number">01</span>-<span class="hljs-number">19</span> <span class="hljs-number">13</span>:<span class="hljs-number">05</span>:<span class="hljs-number">17</span>,<span class="hljs-number">029</span> - INFO - Resposta do servidor: Olá, cliente! Conexão estabelecida.
<span class="hljs-attribute">host_b_client</span>  | <span class="hljs-number">2025</span>-<span class="hljs-number">01</span>-<span class="hljs-number">19</span> <span class="hljs-number">13</span>:<span class="hljs-number">05</span>:<span class="hljs-number">17</span>,<span class="hljs-number">029</span> - INFO - Conexão com o servidor encerrada.

<span class="hljs-attribute">host_a_server</span>  | <span class="hljs-number">2025</span>-<span class="hljs-number">01</span>-<span class="hljs-number">19</span> <span class="hljs-number">13</span>:<span class="hljs-number">05</span>:<span class="hljs-number">17</span>,<span class="hljs-number">029</span> - INFO - Mensagem recebida: Olá, servidor!
<span class="hljs-attribute">host_a_server</span>  | <span class="hljs-number">2025</span>-<span class="hljs-number">01</span>-<span class="hljs-number">19</span> <span class="hljs-number">13</span>:<span class="hljs-number">05</span>:<span class="hljs-number">17</span>,<span class="hljs-number">029</span> - INFO - Conexão com ('<span class="hljs-number">1.2.9.3</span>', <span class="hljs-number">44890</span>) encerrada.
</code></pre>
<p>Podemos ver no container do servidor, que o mesmo está com uma porta listen no endereço 0.0.0.0, ou seja, a porta 6969 está disponível em qualquer uma das interfaces que o servidor possuir.</p>
<pre><code class="lang-apache"><span class="hljs-attribute">root</span>@host_a_server:/app# netstat -nat
<span class="hljs-attribute">Active</span> Internet connections (servers and established)
<span class="hljs-attribute">Proto</span> Recv-Q Send-Q Local Address           Foreign Address         State
<span class="hljs-attribute">tcp</span>        <span class="hljs-number">0</span>      <span class="hljs-number">0</span> <span class="hljs-number">0.0.0.0:6969</span>            <span class="hljs-number">0.0.0.0</span>:*               LISTEN
</code></pre>
<p>Um ponto importante que vale ressaltar é que no contexto TCP/IP, precisamos entender que existem IP’s de origem e destino e portas de origem e destino para uma conexão estabelecida, ou seja, o IP e porta de origem de um host se comunica com o IP e porta de destino de outro host, esse processo acontece através do <a target="_blank" href="https://gitbook.ganeshicmc.com/redes/three-way-handshake">3-way-handshake</a>, mas não vou evoluir o assunto para este caminho, em todo caso se quiser mais detalhes, deixei nas referências um material falando do assunto.</p>
<hr />
<h1 id="heading-vamos-falar-de-docker">Vamos falar de docker</h1>
<p>Aposto que você já teve algum contato com docker, porém mágicamente meio que… em um cenário ideal, tudo meio que funciona certo?</p>
<p>Vamos pensar em um cenário onde temos uma aplicação, seja ela em PHP, Python, Js, tanto faz, vamos chamar ela de APP, um banco de dados, neste caso vou chamar de DB, e um serviço de cache, que simplesmente vou chamar de cache, o docker-compose dele será algo parecido com isso.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
    <span class="hljs-attr">app:</span>
        <span class="hljs-attr">image:</span> <span class="hljs-string">nginx:latest</span>
        <span class="hljs-attr">container_name:</span> <span class="hljs-string">app</span>
    <span class="hljs-attr">db:</span>
        <span class="hljs-attr">image:</span> <span class="hljs-string">mysql:latest</span>
        <span class="hljs-attr">container_name:</span> <span class="hljs-string">db</span>
        <span class="hljs-attr">environment:</span>
            <span class="hljs-attr">MYSQL_ROOT_PASSWORD:</span> <span class="hljs-string">root</span>
            <span class="hljs-attr">MYSQL_DATABASE:</span> <span class="hljs-string">app</span>
            <span class="hljs-attr">MYSQL_USER:</span> <span class="hljs-string">bad_user</span>
            <span class="hljs-attr">MYSQL_PASSWORD:</span> <span class="hljs-string">bad_pass</span>
    <span class="hljs-attr">cache:</span>
        <span class="hljs-attr">image:</span> <span class="hljs-string">redis:latest</span>
        <span class="hljs-attr">container_name:</span> <span class="hljs-string">cache</span>
</code></pre>
<p>Você vai perceber que se tentar subir estes serviços, cada um de forma isolada vai funcionar, porém não vão conseguir se comunicar, isso porque para que os serviços possam se comunicar, precisamos que eles façam parte da mesma rede, lembra?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736291752618/ab7237fd-838d-417e-aaf9-5aaed578ce67.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-verificando-a-rede-dos-containers">Verificando a rede dos containers</h3>
<p>Assim que subimos os serviços, cada um dos hosts/containers vão ter seu próprio endereço de IP, vamos verificar qual endereço foram associados utilizando o comando do docker em conjunto com o <a target="_blank" href="https://jqlang.github.io/jq/download/">jq</a> abaixo:</p>
<pre><code class="lang-bash"><span class="hljs-comment">## Apenas comando do docker</span>
docker container inspect app

<span class="hljs-comment">## Comando do docker filtrando com jq a configuração de Network</span>
docker container inspect app | jq <span class="hljs-string">'.[0].NetworkSettings'</span>
</code></pre>
<p>Utilizando o comando acima, conseguimos ver que o endereço que o host (app) recebeu foi o endereço:</p>
<p><strong>HOST:</strong> 1.2.7.2/24</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"Bridge"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"SandboxID"</span>: <span class="hljs-string">"210f0e9ba9e77201d7e0f3a2948ce31826353c4727d8f45c0bcabb6bf5b020ac"</span>,
  <span class="hljs-attr">"SandboxKey"</span>: <span class="hljs-string">"/var/run/docker/netns/210f0e9ba9e7"</span>,
  <span class="hljs-attr">"Ports"</span>: {
    <span class="hljs-attr">"80/tcp"</span>: <span class="hljs-literal">null</span>
  },
  <span class="hljs-attr">"HairpinMode"</span>: <span class="hljs-literal">false</span>,
  <span class="hljs-attr">"LinkLocalIPv6Address"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"LinkLocalIPv6PrefixLen"</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">"SecondaryIPAddresses"</span>: <span class="hljs-literal">null</span>,
  <span class="hljs-attr">"SecondaryIPv6Addresses"</span>: <span class="hljs-literal">null</span>,
  <span class="hljs-attr">"EndpointID"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"Gateway"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"GlobalIPv6Address"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"GlobalIPv6PrefixLen"</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">"IPAddress"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"IPPrefixLen"</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">"IPv6Gateway"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"MacAddress"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"Networks"</span>: {
    <span class="hljs-attr">"redes-docker_default"</span>: {
      <span class="hljs-attr">"IPAMConfig"</span>: <span class="hljs-literal">null</span>,
      <span class="hljs-attr">"Links"</span>: <span class="hljs-literal">null</span>,
      <span class="hljs-attr">"Aliases"</span>: [
        <span class="hljs-string">"app"</span>,
        <span class="hljs-string">"app"</span>
      ],
      <span class="hljs-attr">"MacAddress"</span>: <span class="hljs-string">"02:42:01:02:07:02"</span>,
      <span class="hljs-attr">"DriverOpts"</span>: <span class="hljs-literal">null</span>,
      <span class="hljs-attr">"NetworkID"</span>: <span class="hljs-string">"961d9113f94092827308148af99793a9ea3d471716a14979b3dcce6683cd5b66"</span>,
      <span class="hljs-attr">"EndpointID"</span>: <span class="hljs-string">"52e065cd20596fae04409ad82488297ba659c483b42527df4445e3b595533cae"</span>,
      <span class="hljs-attr">"Gateway"</span>: <span class="hljs-string">"1.2.7.1"</span>,
      <span class="hljs-attr">"IPAddress"</span>: <span class="hljs-string">"1.2.7.2"</span>,
      <span class="hljs-attr">"IPPrefixLen"</span>: <span class="hljs-number">24</span>,
      <span class="hljs-attr">"IPv6Gateway"</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">"GlobalIPv6Address"</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">"GlobalIPv6PrefixLen"</span>: <span class="hljs-number">0</span>,
      <span class="hljs-attr">"DNSNames"</span>: [
        <span class="hljs-string">"app"</span>,
        <span class="hljs-string">"5ec26cac5ce0"</span>
      ]
    }
  }
}
</code></pre>
<p>Continuando a inspeção, chegamos no seguinte resultado.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Serviço</td><td>IP/PREFIX</td><td>GATEWAY</td></tr>
</thead>
<tbody>
<tr>
<td>app</td><td>1.2.7.2/24</td><td>1.2.7.1</td></tr>
<tr>
<td>db</td><td>1.2.7.3/24</td><td>1.2.7.1</td></tr>
<tr>
<td>cache</td><td>1.2.7.4/24</td><td>1.2.7.1</td></tr>
</tbody>
</table>
</div><p>Ou seja</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737157963383/c4aa4d5a-2f6e-4b06-97cd-31965b022880.png" alt class="image--center mx-auto" /></p>
<p>Ok, ok… então significa que a aplicação consegue falar com o banco de dados e consequentemente a aplicação também consegue falar com o cache, pois os mesmos estão na mesma rede certo?</p>
<p>Exatamente isso 👏👏👏, obviamente que para o contexto do docker existem restrições a nível de firewall que podem fazer com que os hosts não se comuniquem, mas… com o docker-compose.yaml que eu utilizei e com o Docker Compose version v2.20.3 e o docker Docker version 27.3.1, build ce12230. Assim que eu subi a aplicação, o docker utilizou a rede → redes-docker_default que está em modo bridge, permitindo a comunicação entre os serviços que fazem parte desta rede.</p>
<p>para inspecionar essa rede você pode utilizar o comando</p>
<pre><code class="lang-bash">~ docker network inspect redes-docker_default | jq <span class="hljs-string">'.[0].IPAM'</span>
{
  <span class="hljs-string">"Driver"</span>: <span class="hljs-string">"default"</span>,
  <span class="hljs-string">"Options"</span>: null,
  <span class="hljs-string">"Config"</span>: [
    {
      <span class="hljs-string">"Subnet"</span>: <span class="hljs-string">"1.2.7.0/24"</span>,
      <span class="hljs-string">"Gateway"</span>: <span class="hljs-string">"1.2.7.1"</span>
    }
  ]
}
</code></pre>
<p>Ao tentar <a target="_blank" href="https://pt.wikipedia.org/wiki/Ping">pingar</a>, do host da aplicação para o host do banco de dados, percebemos que existe uma resposta. Chegamos a conclusão de que a comunicação existe pois o ping informa quantos pacotes foram transmitidos e quantos destes foram recebidos.</p>
<pre><code class="lang-bash"><span class="hljs-comment">### Acessando o container</span>
~ docker <span class="hljs-built_in">exec</span> -it app bash

<span class="hljs-comment">### Testando a comunicação</span>
root@app:/<span class="hljs-comment"># apt-get install -y iputils-ping</span>
root@app:/<span class="hljs-comment"># ping db</span>
PING db (1.2.7.3) 56(84) bytes of data.
64 bytes from db.redes-docker_default (1.2.7.3): icmp_seq=1 ttl=64 time=0.184 ms
64 bytes from db.redes-docker_default (1.2.7.3): icmp_seq=2 ttl=64 time=0.077 ms
64 bytes from db.redes-docker_default (1.2.7.3): icmp_seq=3 ttl=64 time=0.064 ms
64 bytes from db.redes-docker_default (1.2.7.3): icmp_seq=4 ttl=64 time=0.076 ms
64 bytes from db.redes-docker_default (1.2.7.3): icmp_seq=5 ttl=64 time=0.076 ms
64 bytes from db.redes-docker_default (1.2.7.3): icmp_seq=6 ttl=64 time=0.075 ms
^C
--- db ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5138ms
rtt min/avg/max/mdev = 0.064/0.092/0.184/0.041 ms
</code></pre>
<p>Em algumas situações, os hosts negam as requisições ICMP, fazendo com que o ping seja retornado, neste caso podemos utilizar o telnet, assim validamos se existe algum serviço escutando na porta informada.</p>
<pre><code class="lang-bash">root@app:/<span class="hljs-comment"># telnet db 3306</span>
Trying 1.2.7.3...
Connected to db.
Escape character is <span class="hljs-string">'^]'</span>.
I
5}lNTcaching_sha2_password2<span class="hljs-comment">#08S01Got timeout reading communication packetsConnection closed by foreign host.</span>
</code></pre>
<p>Mais uma forma de testar conectividade é utilizando o <a target="_blank" href="https://nmap.org/">nmap</a>. Com ele podemos não só testar uma porta, mas também quais as portas abertas de um host.</p>
<pre><code class="lang-bash">root@app:/<span class="hljs-comment"># nmap -p 3306 db</span>
Starting Nmap 7.93 ( https://nmap.org ) at 2025-01-18 00:11 UTC
Nmap scan report <span class="hljs-keyword">for</span> db (1.2.7.3)
Host is up (0.00011s latency).
rDNS record <span class="hljs-keyword">for</span> 1.2.7.3: db.redes-docker_default

PORT     STATE SERVICE
3306/tcp open  mysql
MAC Address: 02:42:01:02:07:03 (Unknown)

Nmap <span class="hljs-keyword">done</span>: 1 IP address (1 host up) scanned <span class="hljs-keyword">in</span> 0.30 seconds
</code></pre>
<hr />
<h1 id="heading-bora-aprofundar">Bora aprofundar?</h1>
<p>Sendo bem transparente com você, o básico já passou e talvez… apenas com o que eu falei acima já dá pra ter uma boa noção de como a rede dos containers funciona e também, arrisco a dizer que… é um básico do básico de redes. Os mais entendidos do assunto sabem que tem bastante coisa pra falar ainda, mas… agora vamos dar uma aprofundada 😉👌</p>
<h2 id="heading-dominios-de-broadcast">Domínios de broadcast</h2>
<p>Assim como no mundo da camada 3 do modelo TCP/IP existe um identificador único que chamamos de IP e definimos uma rede através dos prefixos, fazendo com que os hosts participantes das redes possam se comunicar, na camada 2 também existe um identificador único que chamamos de MAC ou endereço físico e também podem se comunicar MAC’s que participam do domínio de broadcast. Partindo disso vamos ver os mesmos hosts de antes de uma perspectiva diferente.</p>
<p>Primeiramente, vamos ver todas as interfaces que fazem parte do domínio de broadcast da rede → redes-docker_default, para isso precisamos saber qual bridge foi criada pelo docker.</p>
<pre><code class="lang-bash">docker network ls | grep redes-docker_default
NETWORK ID     NAME                         DRIVER    SCOPE
961d9113f940   redes-docker_default         bridge    <span class="hljs-built_in">local</span>
</code></pre>
<p>Com o comando acima, chegamos no NETWORK ID 961d9113f940, o docker cria uma bridge com o mesmo id, porém com o prefixo “br-”, conseguimos ver as interfaces virtuais associadas a bridge criada com o seguinte comando.</p>
<pre><code class="lang-bash">&gt; ip link show master br-961d9113f940
39: vethbf30c22@if38: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue master br-961d9113f940 state UP mode DEFAULT group default
    link/ether b6:62:83:bd:3c:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0
43: veth512189f@if42: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue master br-961d9113f940 state UP mode DEFAULT group default
    link/ether ce:c0:66:fb:7a:a9 brd ff:ff:ff:ff:ff:ff link-netnsid 2
45: vethb57ac2a@if44: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue master br-961d9113f940 state UP mode DEFAULT group default
    link/ether 5a:6a:f4:78:1c:9d brd ff:ff:ff:ff:ff:ff link-netnsid 1
</code></pre>
<p>Assim chegamos nos seguintes endereços fisicos associados a bridge.</p>
<p><code>b6:62:83:bd:3c:88</code></p>
<p><code>ce:c0:66:fb:7a:a9</code></p>
<p><code>5a:6a:f4:78:1c:9d</code></p>
<p>Bora descobrir quem é cada um?</p>
<p>Primeiramente precisamos entender que o docker relaciona uma interface virtual externa ao container com uma interface física dentro do container através do <a target="_blank" href="https://man7.org/linux/man-pages/man4/veth.4.html">veth pair</a>, onde uma espécie de túnel é criado, relacionando essas duas interfaces.</p>
<p>Vamos acessar o container e verificar qual o endereço mac está associado a ela e o indice externo que ela recebeu.</p>
<pre><code class="lang-bash">❯ docker <span class="hljs-built_in">exec</span> -it app bash
root@5ec26cac5ce0:/<span class="hljs-comment"># ip link</span>
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
38: eth0@if39: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 02:42:01:02:07:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
</code></pre>
<p>Podemos ver que o mac do host app internamente é <code>02:42:01:02:07:02</code> e o índice associado a ele é o 39, podemos ver isto pois logo após o eth0 temos o <code>@if39</code>. Com esta informação em mente, vamos sair do container e verificar qual é a interface associada a bridge que está relacionada a interface do container.</p>
<p>Primeiramente, vamos localizar a interface com o índice 39, e então partindo da informação da interface virtual, vamos chegar até o endereço mac associado a ela.</p>
<pre><code class="lang-bash"><span class="hljs-comment">### Localizando interface</span>
ip link | grep <span class="hljs-string">"^39:"</span>
39: vethbf30c22@if38: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue master br-961d9113f940 state UP mode DEFAULT group default

<span class="hljs-comment">### Verificando o MAC da interface</span>
ip link show dev vethbf30c22
39: vethbf30c22@if38: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue master br-961d9113f940 state UP mode DEFAULT group default
    link/ether b6:62:83:bd:3c:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0
</code></pre>
<p>Assim conseguimos descobrir que, o endereço MAC <code>b6:62:83:bd:3c:88</code> é na verdade do container app, e que o endereço mac que aparece na bridge na verdade está fazendo o papel de conectar a interface externa com o endereço físico <code>b6:62:83:bd:3c:88</code> a interface eth0 interna com o endereço <code>02:42:01:02:07:02</code></p>
<p>Caso você queira inspecionar diretamente a bridge que foi gerenciada pelo docker, podemos utilizar o comando abaixo</p>
<pre><code class="lang-bash">&gt; docker network inspect redes-docker_default | jq .[0].Containers
</code></pre>
<p>O resultado será o seguinte</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"4a51cc332df584771fd3ec8d5c229073b1971d2167d3385cd9376ee0b7761a04"</span>: {
    <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"db"</span>,
    <span class="hljs-attr">"EndpointID"</span>: <span class="hljs-string">"2be625310559ed29d7d9571f30f43668cc86c0f14612eb0e90ebffd1d51d88e3"</span>,
    <span class="hljs-attr">"MacAddress"</span>: <span class="hljs-string">"02:42:01:02:07:03"</span>,
    <span class="hljs-attr">"IPv4Address"</span>: <span class="hljs-string">"1.2.7.3/24"</span>,
    <span class="hljs-attr">"IPv6Address"</span>: <span class="hljs-string">""</span>
  },
  <span class="hljs-attr">"5ec26cac5ce0ddbb299aca8368b7ca77d9149b1ea378e5949b9092c4fa93e586"</span>: {
    <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"app"</span>,
    <span class="hljs-attr">"EndpointID"</span>: <span class="hljs-string">"52e065cd20596fae04409ad82488297ba659c483b42527df4445e3b595533cae"</span>,
    <span class="hljs-attr">"MacAddress"</span>: <span class="hljs-string">"02:42:01:02:07:02"</span>,
    <span class="hljs-attr">"IPv4Address"</span>: <span class="hljs-string">"1.2.7.2/24"</span>,
    <span class="hljs-attr">"IPv6Address"</span>: <span class="hljs-string">""</span>
  },
  <span class="hljs-attr">"ad888d9e5cbd6a84d868d574b94744d16ef853711e5c4dcbaad4007e07eebd31"</span>: {
    <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"cache"</span>,
    <span class="hljs-attr">"EndpointID"</span>: <span class="hljs-string">"ad7604bd382e4f7480303a1b2ca6e9f414af7b3fa54af8c4e5646c35af8a6bdf"</span>,
    <span class="hljs-attr">"MacAddress"</span>: <span class="hljs-string">"02:42:01:02:07:04"</span>,
    <span class="hljs-attr">"IPv4Address"</span>: <span class="hljs-string">"1.2.7.4/24"</span>,
    <span class="hljs-attr">"IPv6Address"</span>: <span class="hljs-string">""</span>
  }
}
</code></pre>
<p>Assim conseguimos ver todos os MAC’s associados aos containers.</p>
<hr />
<h1 id="heading-internet-das-coisas-iot"><strong>Internet das Coisas (IoT)</strong></h1>
<p>Para os Dev’s que chegaram até aqui… bora falar de uma coisa muito legal que é internet das coisas, e… eu aposto que você em algum momento já se perguntou… ué? mas como que o meu celular sabe que a minha TV está na minha casa? ou… como a Alexa sabe que existe uma lâmpada ou uma câmera de vigilância? Pois então meu amigo… o mundo do dev que conhece redes também é muito legal, vem comigo.</p>
<p>Primeiramente a gente precisa entender que não é somente o broadcast que ajuda a gente com o processo de descoberta, afinal o broadcast tem como funcionalidade principal, enviar uma mensagem para todos os participantes de uma rede.</p>
<p>Algumas estratégias envolvem:</p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Broadcasting_\(networking\)">Broadcast</a></p>
<p><a target="_blank" href="https://pt.wikipedia.org/wiki/Multicast">Multicast</a></p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol">UPNP → SSDP (Simple Service Discovery Protocol)</a></p>
<h3 id="heading-para-a-descoberta-usando-broadcast">Para a descoberta usando Broadcast</h3>
<p>Neste exemplo abaixo, vamos fazer com que dois hosts se identifiquem através de broadcast, vou utilizar Python, mas tenho certeza que você vai encontrar algo na sua linguagem de preferência.</p>
<h4 id="heading-docker-composeyaml">docker-compose.yaml</h4>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">device1:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">.</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">device1</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">DEVICE_NAME=Device1</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-attr">iot_network:</span>
        <span class="hljs-attr">ipv4_address:</span> <span class="hljs-number">192.168</span><span class="hljs-number">.1</span><span class="hljs-number">.10</span>

  <span class="hljs-attr">device2:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">.</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">device2</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">DEVICE_NAME=Device2</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-attr">iot_network:</span>
        <span class="hljs-attr">ipv4_address:</span> <span class="hljs-number">192.168</span><span class="hljs-number">.1</span><span class="hljs-number">.11</span>

<span class="hljs-attr">networks:</span>
  <span class="hljs-attr">iot_network:</span>
    <span class="hljs-attr">driver:</span> <span class="hljs-string">bridge</span>
    <span class="hljs-attr">ipam:</span>
      <span class="hljs-attr">config:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">subnet:</span> <span class="hljs-number">192.168</span><span class="hljs-number">.1</span><span class="hljs-number">.0</span><span class="hljs-string">/24</span>
</code></pre>
<h4 id="heading-dockerfile">dockerfile</h4>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> python:<span class="hljs-number">3.9</span>-slim

<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>
<span class="hljs-keyword">COPY</span><span class="bash"> broadcast.py /app/broadcast.py</span>
<span class="hljs-keyword">RUN</span><span class="bash"> pip install --no-cache-dir --upgrade pip</span>

<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"python"</span>, <span class="hljs-string">"/app/broadcast.py"</span>]</span>
</code></pre>
<h4 id="heading-broadcastpyhttpbroadcastpy"><a target="_blank" href="http://broadcast.py">broadcast.py</a></h4>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> socket
<span class="hljs-keyword">import</span> threading
<span class="hljs-keyword">import</span> time

BROADCAST_IP = <span class="hljs-string">"255.255.255.255"</span>
PORT = <span class="hljs-number">5005</span>
DEVICE_NAME = <span class="hljs-string">"IoT Device"</span>

discovered_devices = set()
stop_discovery = threading.Event()


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">broadcast_sender</span>():</span>
    <span class="hljs-keyword">with</span> socket.socket(
        socket.AF_INET,
        socket.SOCK_DGRAM,
        socket.IPPROTO_UDP
    ) <span class="hljs-keyword">as</span> sender_socket:
        sender_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, <span class="hljs-number">1</span>)
        <span class="hljs-keyword">while</span> <span class="hljs-keyword">not</span> stop_discovery.is_set():
            message = <span class="hljs-string">f"DISCOVER from <span class="hljs-subst">{DEVICE_NAME}</span>"</span>
            print(<span class="hljs-string">f"[<span class="hljs-subst">{DEVICE_NAME}</span>] Enviando broadcast: <span class="hljs-subst">{message}</span>"</span>)
            sender_socket.sendto(message.encode(), (BROADCAST_IP, PORT))
            time.sleep(<span class="hljs-number">5</span>)


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">broadcast_receiver</span>():</span>
    <span class="hljs-keyword">with</span> socket.socket(
        socket.AF_INET,
        socket.SOCK_DGRAM,
        socket.IPPROTO_UDP
    ) <span class="hljs-keyword">as</span> receiver_socket:
        receiver_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, <span class="hljs-number">1</span>)
        receiver_socket.bind((<span class="hljs-string">""</span>, PORT))
        print(<span class="hljs-string">f"[<span class="hljs-subst">{DEVICE_NAME}</span>] Aguardando mensagens de broadcast "</span>
              <span class="hljs-string">f"na porta <span class="hljs-subst">{PORT}</span>..."</span>)

        <span class="hljs-keyword">while</span> <span class="hljs-keyword">not</span> stop_discovery.is_set():
            message, address = receiver_socket.recvfrom(<span class="hljs-number">1024</span>)
            decoded_message = message.decode()
            sender_ip = address[<span class="hljs-number">0</span>]

            print(<span class="hljs-string">f"[<span class="hljs-subst">{DEVICE_NAME}</span>] Recebeu mensagem de <span class="hljs-subst">{sender_ip}</span>: "</span>
                  <span class="hljs-string">f"<span class="hljs-subst">{decoded_message}</span>"</span>)

            <span class="hljs-keyword">if</span> (sender_ip <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> discovered_devices <span class="hljs-keyword">and</span>
                    <span class="hljs-string">"DISCOVER"</span> <span class="hljs-keyword">in</span> decoded_message):
                discovered_devices.add(sender_ip)
                print(<span class="hljs-string">f"[<span class="hljs-subst">{DEVICE_NAME}</span>] Dispositivo descoberto: <span class="hljs-subst">{sender_ip}</span>"</span>)

                response = <span class="hljs-string">f"Hello from <span class="hljs-subst">{DEVICE_NAME}</span>!"</span>
                print(<span class="hljs-string">f"[<span class="hljs-subst">{DEVICE_NAME}</span>] Respondendo a <span class="hljs-subst">{sender_ip}</span>: <span class="hljs-subst">{response}</span>"</span>)
                receiver_socket.sendto(response.encode(), address)

                stop_discovery.set()


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    threading.Thread(target=broadcast_receiver, daemon=<span class="hljs-literal">True</span>).start()
    broadcast_sender()
</code></pre>
<p>O retorno da execução do exemplo acíma vai ser o seguinte</p>
<pre><code class="lang-bash">device2  | [IoT Device] Enviando broadcast: DISCOVER from IoT Device
device2  | [IoT Device] Aguardando mensagens de broadcast na porta 5005...
device2  | [IoT Device] Recebeu mensagem de 192.168.1.11: DISCOVER from IoT Device
device2  | [IoT Device] Dispositivo descoberto: 192.168.1.11
device2  | [IoT Device] Respondendo a 192.168.1.11: Hello from IoT Device!

device1  | [IoT Device] Enviando broadcast: DISCOVER from IoT Device
device1  | [IoT Device] Aguardando mensagens de broadcast na porta 5005...
device1  | [IoT Device] Recebeu mensagem de 192.168.1.10: DISCOVER from IoT Device
device1  | [IoT Device] Dispositivo descoberto: 192.168.1.10
device1  | [IoT Device] Respondendo a 192.168.1.10: Hello from IoT Device!

device2 exited with code 0
device1 exited with code 0
</code></pre>
<h3 id="heading-para-descoberta-upnp">Para descoberta UPNP</h3>
<h4 id="heading-dockerfile-1">dockerfile</h4>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> python:<span class="hljs-number">3.9</span>-slim

<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

<span class="hljs-keyword">COPY</span><span class="bash"> upnp_discovery.py /app/upnp_discovery.py</span>

<span class="hljs-keyword">RUN</span><span class="bash"> pip install --no-cache-dir --upgrade pip</span>

<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"python"</span>, <span class="hljs-string">"/app/upnp_discovery.py"</span>]</span>
</code></pre>
<h4 id="heading-docker-composeyaml-1">docker-compose.yaml</h4>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">device3:</span>
    <span class="hljs-attr">build:</span>
      <span class="hljs-attr">context:</span> <span class="hljs-string">.</span>
      <span class="hljs-attr">dockerfile:</span> <span class="hljs-string">Dockerfile</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">device3</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">DEVICE_NAME=Device3</span>

  <span class="hljs-attr">device4:</span>
    <span class="hljs-attr">build:</span>
      <span class="hljs-attr">context:</span> <span class="hljs-string">.</span>
      <span class="hljs-attr">dockerfile:</span> <span class="hljs-string">Dockerfile</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">device4</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">DEVICE_NAME=Device4</span>

<span class="hljs-attr">networks:</span>
  <span class="hljs-attr">default:</span>
    <span class="hljs-attr">driver:</span> <span class="hljs-string">bridge</span>
</code></pre>
<h4 id="heading-upnpdiscoverypyhttpdiscoverypy">upnp_<a target="_blank" href="http://discovery.py">discovery.py</a></h4>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> socket
<span class="hljs-keyword">import</span> threading
<span class="hljs-keyword">import</span> time

MULTICAST_IP = <span class="hljs-string">"239.255.255.250"</span>
PORT = <span class="hljs-number">1900</span>
DEVICE_NAME = <span class="hljs-string">"UPnP Device"</span>
SERVICE_TYPE = <span class="hljs-string">"ssdp:all"</span>
MX = <span class="hljs-number">2</span>

discovered_devices = set()
stop_discovery = threading.Event()


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">ssdp_sender</span>():</span>
    <span class="hljs-keyword">with</span> socket.socket(
        socket.AF_INET,
        socket.SOCK_DGRAM,
        socket.IPPROTO_UDP
    ) <span class="hljs-keyword">as</span> sender_socket:
        sender_socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, <span class="hljs-number">2</span>)
        message = (
            <span class="hljs-string">"M-SEARCH * HTTP/1.1\r\n"</span>
            <span class="hljs-string">f"HOST: <span class="hljs-subst">{MULTICAST_IP}</span>:<span class="hljs-subst">{PORT}</span>\r\n"</span>
            <span class="hljs-string">"MAN: \"ssdp:discover\"\r\n"</span>
            <span class="hljs-string">f"ST: <span class="hljs-subst">{SERVICE_TYPE}</span>\r\n"</span>
            <span class="hljs-string">f"MX: <span class="hljs-subst">{MX}</span>\r\n"</span>
            <span class="hljs-string">"\r\n"</span>
        )
        <span class="hljs-keyword">while</span> <span class="hljs-keyword">not</span> stop_discovery.is_set():
            print(
                <span class="hljs-string">f"[<span class="hljs-subst">{DEVICE_NAME}</span>] Enviando mensagem SSDP:\n<span class="hljs-subst">{message.strip()}</span>"</span>
            )
            sender_socket.sendto(message.encode(), (MULTICAST_IP, PORT))
            time.sleep(<span class="hljs-number">5</span>)


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">ssdp_receiver</span>():</span>
    <span class="hljs-keyword">with</span> socket.socket(
        socket.AF_INET,
        socket.SOCK_DGRAM,
        socket.IPPROTO_UDP
    ) <span class="hljs-keyword">as</span> receiver_socket:
        receiver_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, <span class="hljs-number">1</span>)
        receiver_socket.bind((<span class="hljs-string">""</span>, PORT))

        mreq = socket.inet_aton(MULTICAST_IP) + socket.INADDR_ANY.to_bytes(
            <span class="hljs-number">4</span>,
            <span class="hljs-string">"big"</span>
        )
        receiver_socket.setsockopt(
            socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq
        )

        print(<span class="hljs-string">f"[<span class="hljs-subst">{DEVICE_NAME}</span>] Aguardando respostas SSDP na porta <span class="hljs-subst">{PORT}</span>..."</span>)

        <span class="hljs-keyword">while</span> <span class="hljs-keyword">not</span> stop_discovery.is_set():
            <span class="hljs-keyword">try</span>:
                message, address = receiver_socket.recvfrom(<span class="hljs-number">1024</span>)
                sender_ip = address[<span class="hljs-number">0</span>]
                decoded_message = message.decode()

                <span class="hljs-keyword">if</span> sender_ip <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> discovered_devices:
                    discovered_devices.add(sender_ip)
                    print(<span class="hljs-string">f"[<span class="hljs-subst">{DEVICE_NAME}</span>] Resposta recebida de <span class="hljs-subst">{sender_ip}</span>:\n<span class="hljs-subst">{decoded_message.strip()}</span>"</span>)
                    stop_discovery.set()
            <span class="hljs-keyword">except</span> socket.timeout:
                <span class="hljs-keyword">pass</span>


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    threading.Thread(target=ssdp_receiver, daemon=<span class="hljs-literal">True</span>).start()
    ssdp_sender()
</code></pre>
<p>A resposta do script acima vai se parecer com esta abaixo, informando que os dispositivos passaram pelo processo de discover.</p>
<pre><code class="lang-bash">device4  | [UPnP Device] Aguardando respostas SSDP na porta 1900...
device4  | [UPnP Device] Enviando mensagem SSDP:
device4  | M-SEARCH * HTTP/1.1
device4  | HOST: 239.255.255.250:1900
device4  | MAN: <span class="hljs-string">"ssdp:discover"</span>
device4  | ST: ssdp:all
device4  | MX: 2
device4  | [UPnP Device] Resposta recebida de 1.2.8.3:
device4  | M-SEARCH * HTTP/1.1
device4  | HOST: 239.255.255.250:1900
device4  | MAN: <span class="hljs-string">"ssdp:discover"</span>
device4  | ST: ssdp:all
device4  | MX: 2
device4 exited with code 0


device3  | [UPnP Device] Enviando mensagem SSDP:
device3  | M-SEARCH * HTTP/1.1
device3  | HOST: 239.255.255.250:1900
device3  | MAN: <span class="hljs-string">"ssdp:discover"</span>
device3  | ST: ssdp:all
device3  | MX: 2
device3  | [UPnP Device] Aguardando respostas SSDP na porta 1900...
device3  | [UPnP Device] Enviando mensagem SSDP:
device3  | M-SEARCH * HTTP/1.1
device3  | HOST: 239.255.255.250:1900
device3  | MAN: <span class="hljs-string">"ssdp:discover"</span>
device3  | ST: ssdp:all
device3  | MX: 2
device3  | [UPnP Device] Resposta recebida de 1.2.8.2:
device3  | M-SEARCH * HTTP/1.1
device3  | HOST: 239.255.255.250:1900
device3  | MAN: <span class="hljs-string">"ssdp:discover"</span>
device3  | ST: ssdp:all
device3  | MX: 2
device3 exited with code 0
</code></pre>
<hr />
<h1 id="heading-conclusao">Conclusão</h1>
<p>O mundo do desenvolvimento não se limita às fronteiras do código, se permita aprofundar e olhar o que existe embaixo do capô, tenho certeza de que quanto mais deep você se deixar ir, mais apaixonado você vai ficar com o que a tecnologia tem pra te mostrar. Não sabemos e nunca vamos saber de tudo, mas… se deixe desbravar e se veja como um eterno aprendiz, alguém em constante evolução, pronto para transformar curiosidade em conhecimento e desafios em oportunidades. Afinal, a magia da tecnologia está justamente em sua infinita capacidade de nos surpreender e ensinar algo novo a cada dia.</p>
<p>Muito obrigado por ter chegado até aqui…</p>
<hr />
<h1 id="heading-referencias">Referências</h1>
<ul>
<li><p>Network linux</p>
<ul>
<li><p><a target="_blank" href="https://wiki.archlinux.org/title/Network_bridge">https://wiki.archlinux.org/title/Network_bridge</a></p>
</li>
<li><p><a target="_blank" href="https://man7.org/linux/man-pages/man4/veth.4.html">https://man7.org/linux/man-pages/man4/veth.4.html</a></p>
</li>
</ul>
</li>
<li><p>Docker Network</p>
<ul>
<li><a target="_blank" href="https://docs.docker.com/engine/network/">https://docs.docker.com/engine/network/</a></li>
</ul>
</li>
<li><p>Subnet domain</p>
<ul>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Subnet">https://en.wikipedia.org/wiki/Subnet</a></li>
</ul>
</li>
<li><p>Broadcast domain</p>
<ul>
<li><a target="_blank" href="https://networklessons.com/switching/broadcast-domain">https://networklessons.com/switching/broadcast-domain</a></li>
</ul>
</li>
<li><p>SSDP / UPNP</p>
<ul>
<li><p><a target="_blank" href="https://nordvpn.com/pt-br/blog/upnp-o-que-e/">https://nordvpn.com/pt-br/blog/upnp-o-que-e/</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol">https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol</a></p>
</li>
</ul>
</li>
<li><p>TCP range ports</p>
<ul>
<li><p><a target="_blank" href="https://datatracker.ietf.org/doc/html/rfc1340">https://datatracker.ietf.org/doc/html/rfc1340</a></p>
</li>
<li><p><a target="_blank" href="https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml">https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml</a></p>
</li>
<li><p><a target="_blank" href="https://www.rfc-editor.org/rfc/rfc6335.html">https://www.rfc-editor.org/rfc/rfc6335.html</a></p>
</li>
</ul>
</li>
<li><p>TCP</p>
<ul>
<li><a target="_blank" href="https://gitbook.ganeshicmc.com/redes/three-way-handshake">https://gitbook.ganeshicmc.com/redes/three-way-handshake</a></li>
</ul>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Arroz com feijão: A base nutritiva para projetos que funcionam]]></title><description><![CDATA[Resumo
Neste artigo vamos passar literalmente pelo mínimo. Começou agora? não sabe o que o teu projeto precisa para sobreviver as alterações do dia a dia? fica comigo que a gente vai passar pelo que provavelmente ninguém vai te cobrar pra fazer, mas ...]]></description><link>https://blog.maicol.dev/arroz-com-feijao-a-base-nutritiva-para-projetos-que-funcionam</link><guid isPermaLink="true">https://blog.maicol.dev/arroz-com-feijao-a-base-nutritiva-para-projetos-que-funcionam</guid><category><![CDATA[Code Quality]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Maicol Kaiser]]></dc:creator><pubDate>Sat, 21 Dec 2024 13:31:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732640097533/0bc01c75-f4d1-4aeb-9b18-b3dfc514d678.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<h1 id="heading-resumo">Resumo</h1>
<p>Neste artigo vamos passar literalmente pelo mínimo. Começou agora? não sabe o que o teu projeto precisa para sobreviver as alterações do dia a dia? fica comigo que a gente vai passar pelo que provavelmente ninguém vai te cobrar pra fazer, mas sério… isso é o mínimo.</p>
<hr />
<h1 id="heading-so-voce-sabe-e-talvez-nem-voce-saiba-mais">Só você sabe?… e talvez nem você saiba mais!</h1>
<p>Já se deparou com a situação de ter que sustentar um produto, e ninguém sabe te dizer onde… como, e do que esse produto se alimenta?. Parece impossível né? afinal como que um sistema esta no ar e ninguém sabe de nada?. Pois então irmão, é muito mais comum do que parece.</p>
<p>Na rotina sufocante dos desenvolvedores é muito comum a sensação de urgência e sinceramente… se você se deixar levar por este ritmo, você vai ser engolido.</p>
<p>Com toda certeza, depois de tanto tempo trabalhando com desenvolvimento, uma das frases que mais ouvi ao longo da minha carreira foi: “não dá tempo”, e consequentemente, pilhas e pilhas de linha de código sobem sem o mínimo de empatia para a produção. Empatia? como assim…? sim sim, empatia, tenho certeza que você não está pensando no próximo desenvolvedor que vai olhar para o código que você escreveu, e arrisco a dizer que, não pensou em você mesmo.</p>
<p>Meses se passaram desde o ultimo commit naquele projeto esquecido que você deu manutenção, e olha que incrível, ele deu problema, e agora? quem foi o dev que escreveu aquelas linhas de código? vixx… foi eu mesmo 😅, mas… sei lá! faz tanto tempo, nem sinto que foi eu quem escreveu aquilo 🤷, já não me reconheço mais naqueles linhas de código.</p>
<p>É meio louco pensar nisso, mas, sim, você já não é mais o mesmo, e naquele momento só se preocupou em entregar a solução, e muito provável que achou completa perda de tempo investir algum tempo na documentação do projeto. Agora você se vê tendo que fazer o caminho do zero, entendendo novamente o fluxo inteiro, e tendo que investir novamente horas até chegar na solução.</p>
<p>A conclusão que eu cheguei com isto é, <strong>nunca é perda de tempo investir alguns minutos dando contexto suficiente para o seu “eu” do futuro</strong>, tenha empatia, nem que seja consigo mesmo, se é um comando, anote, coloque exemplos, explique como se estivesse explicando para uma criança, tenho certeza que você vai agradecer o seu “eu” do passado.</p>
<hr />
<h1 id="heading-como-sobe-isso-aqui">Como sobe isso aqui?</h1>
<p>Assim como no tópico anterior, este aqui fala um pouco sobre empatia.</p>
<p>Imagine-se na situação de iniciar em uma empresa, onboard vai onboard vem, e em algum momento chega até o seu computador o sistema ao qual você vai dar suporte. Uma semana se passou e você ainda não conseguiu subir o dito cujo. Não acredita?… Rede do docker?… Migrations sendo rodadas na mão? variaveis de ambientes não documentadas? falta de permissão?… Fala com um, fala com outro, cada qual te da uma fração de informação e no final do dia… ninguém sabe exatamente como que a disgraça do programa sobe do inicio ao fim.</p>
<p>Já passei por algumas empresas e muitas delas não investiram sequer um dia automatizando o processo de build do projeto. Este comportamento agride diretamente o tempo que um desenvolvedor começa a se tornar produtivo para a empresa, sem falar da percepção de maturidade do sistema.</p>
<p>A minha recomendação é: se eu demoro mais de minutos para subir um projeto, algo de errado não está certo. Atualmente existem diversas formas de automatizar o processo de build do sistema, seja através de bash scripts ou makefiles;</p>
<p>Como um profissional de respeito, é seu dever se preocupar com o mínimo. Como instalar e configurar o seu sistema, como usar e preferencialmente com exemplos de uso. Não esqueça que se for necessário permissões adicionais para sustentar o sistema, uma boa documentação deve ajudar o desenvolvedor, guiando ele para abertura de chamados ou aquisição das devidas permissões.</p>
<p>Abaixo vou deixar um exemplo de readme, ele questiona alguns pontos que vejo como interessantes quando tenho o primeiro contato com o sistema, e… só pra reforçar… é o mínimo.</p>
<p><strong>Exemplo de readme</strong>:</p>
<pre><code class="lang-markdown"><span class="hljs-section">## 📝 <span class="hljs-strong">**Descrição**</span></span>

<span class="hljs-bullet">*</span> Qual o objetivo do projeto? 
<span class="hljs-bullet">*</span> Qual problema ele resolve? 
<span class="hljs-bullet">*</span> Quais as principais funcionalidades?

<span class="hljs-section">## 🛠 <span class="hljs-strong">**Dependencias**</span></span>

<span class="hljs-bullet">*</span> Este serviço depende de algum outro serviço ou ferramenta?
<span class="hljs-bullet">*</span> Este serviço depende de algum cadastro em alguma plataforma ou permissão?

<span class="hljs-section">## 🚀 <span class="hljs-strong">**Como rodar o projeto?**</span></span>

<span class="hljs-bullet">*</span> Quais são os passos necessários para rodar o projeto?
<span class="hljs-bullet">*</span> Quais são as dependências necessárias? Docker? VPN? Certificado?

<span class="hljs-section">## 🧠 Como contribuir para o projeto?</span>

<span class="hljs-bullet">*</span> A branch principal é a <span class="hljs-code">`main`</span>?
<span class="hljs-bullet">*</span> Este projeto utiliza TAG's para versionamento?
<span class="hljs-bullet">*</span> Respeitamos os testes de cobertura de código?
</code></pre>
<hr />
<h1 id="heading-testar-pra-que">Testar pra quê?</h1>
<p>Tá… eu sei, mais um artigo falando sobre testes… mas sério, você confia no seu código? sim!? pois não deveria! Você mente pra você o tempo todo, e vai por mim, o seu código também, confiar no próprio código não é reflexo de senioridade, e sim o completo oposto, você está sendo imaturo, deixe a sindrome do corno pra trás, não seja o ultimo a saber sobre o erro que seu cógido está gerando.</p>
<p>Mudanças acontecem com frequencia em um código vivo, código que não muda, provavelmente ou está morto ou chegou em um nível de abstração invejável.</p>
<p>Testes não devem ser tratados como opcional, e sim como motivo de orgulho. Pense só… qual a melhor forma de provar que você testou?! mostrando o teste ué!. Dizer que viu funcionar em uma única execução não garante absolutamente nada.</p>
<p>Tem preguiça de testar?… é no mínimo estranho… pois o reflexo da falta de testes vai gerar muito mais horas de trabalho que o tempo dedicado para escrita dos testes.</p>
<p>Testes, acredite ou não, fazem parte do mínimo…</p>
<p>Vamos ver como fazer um teste, bem básico, só pra você ter uma noção do esforço. Bora lá!</p>
<p>Como podemos ver, o objetivo desta classe é validar se o texto informado tem palavão. O código não tem como objetivo atender questões de arquitetura de software e as melhores práticas de mercado, to tentando ser didatico ok?</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BadWordsFilter</span>
</span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">array</span> $badWords;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">array</span> $badWords</span>)
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;badWords = $badWords;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">containsBadWords</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $text</span>): <span class="hljs-title">bool</span>
    </span>{
        $wordsInText = <span class="hljs-keyword">$this</span>-&gt;extractWords($text);

        <span class="hljs-keyword">foreach</span> ($wordsInText <span class="hljs-keyword">as</span> $word) {
            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">$this</span>-&gt;isBadWord($word)) {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
            }
        }

        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">extractWords</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $text</span>): <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-comment">// Remove caracteres especiais e retorna uma lista de palavras</span>
        <span class="hljs-keyword">return</span> preg_split(<span class="hljs-string">'/\s+/'</span>, strtolower(trim(preg_replace(<span class="hljs-string">'/[^\w\s]/'</span>, <span class="hljs-string">''</span>, $text))));
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isBadWord</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> $word</span>): <span class="hljs-title">bool</span>
    </span>{
        <span class="hljs-comment">// Verifica se a palavra está na lista de palavras proibidas</span>
        <span class="hljs-keyword">return</span> in_array($word, <span class="hljs-keyword">$this</span>-&gt;badWords, <span class="hljs-literal">true</span>);
    }
}
</code></pre>
<p>No teste abaixo conseguimos validar os seguintes pontos.</p>
<ul>
<li><p>Um caminho feliz, ou seja, o texto informado tem um palavrão que foi previamente mapeado.</p>
</li>
<li><p>Outro caminho feliz é, o texto informado não tem palavrão</p>
</li>
<li><p>O código também tem a capacidade de identificar uma palavra mesmo com letras maiusculas e minusculas.</p>
</li>
<li><p>O código consegue detectar palavrão mesmo contendo caracteres especiais</p>
</li>
<li><p>E o código também lida bem com textos em branco.</p>
</li>
</ul>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">use</span> <span class="hljs-title">PHPUnit</span>\<span class="hljs-title">Framework</span>\<span class="hljs-title">TestCase</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BadWordsFilterTest</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">TestCase</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testContainsBadWordsReturnsTrueWhenTextContainsBadWord</span>(<span class="hljs-params"></span>)
    </span>{
        $filter = <span class="hljs-keyword">new</span> BadWordsFilter([<span class="hljs-string">'badword'</span>, <span class="hljs-string">'offensive'</span>]);

        <span class="hljs-keyword">$this</span>-&gt;assertTrue($filter-&gt;containsBadWords(<span class="hljs-string">'This text contains a badword.'</span>));
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testContainsBadWordsReturnsFalseWhenTextDoesNotContainBadWord</span>(<span class="hljs-params"></span>)
    </span>{
        $filter = <span class="hljs-keyword">new</span> BadWordsFilter([<span class="hljs-string">'badword'</span>, <span class="hljs-string">'offensive'</span>]);

        <span class="hljs-keyword">$this</span>-&gt;assertFalse($filter-&gt;containsBadWords(<span class="hljs-string">'This is a clean text.'</span>));
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testContainsBadWordsIgnoresCase</span>(<span class="hljs-params"></span>)
    </span>{
        $filter = <span class="hljs-keyword">new</span> BadWordsFilter([<span class="hljs-string">'badword'</span>, <span class="hljs-string">'offensive'</span>]);

        <span class="hljs-keyword">$this</span>-&gt;assertTrue($filter-&gt;containsBadWords(<span class="hljs-string">'This text contains a BADWORD.'</span>));
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testContainsBadWordsIgnoresSpecialCharacters</span>(<span class="hljs-params"></span>)
    </span>{
        $filter = <span class="hljs-keyword">new</span> BadWordsFilter([<span class="hljs-string">'badword'</span>, <span class="hljs-string">'offensive'</span>]);

        <span class="hljs-keyword">$this</span>-&gt;assertTrue($filter-&gt;containsBadWords(<span class="hljs-string">'This text contains a badword!'</span>));
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">testContainsBadWordsHandlesEmptyText</span>(<span class="hljs-params"></span>)
    </span>{
        $filter = <span class="hljs-keyword">new</span> BadWordsFilter([<span class="hljs-string">'badword'</span>, <span class="hljs-string">'offensive'</span>]);

        <span class="hljs-keyword">$this</span>-&gt;assertFalse($filter-&gt;containsBadWords(<span class="hljs-string">''</span>));
    }
}
</code></pre>
<p>Como podemos ver, em momento algum eu precisei testar diretamente os métodos privados, afinal, a interface pública da classe, expõe a abstração que o cliente tem interesse, os detalhes que giram em torno dessa abstração precisam ser testadas mudando o input, mas usando o mesmo método público. Então… isso significa que eu não deva testar métodos privados? Não não, segura ai… extremos são ruins, e eu evito me guiar por eles, quando eu desenvolvo, espero seguir um meio termo, e isso envolve testes também. Eventualmente um método com mais de mil linhas vai passar na sua frente e existe uma chance de ele ser privado, e antes de fazer qualquer alteração nele, comece escrevendo testes com o comportamento do método coberto comece renomeando as variaveis para algo mais palatável, extraia alguns métodos e siga sua refatoração se guiando pelo teste.</p>
<hr />
<h1 id="heading-conclusao">Conclusão</h1>
<p>Obviamente muitos outros pontos são de extrema importancia para um sistema que resista as evoluções solicitadas pelo time de produto, seja eles monitoramente, entrega contínua, gestão de segredos, tratamento de erros, estratégias de backup, etc.</p>
<p>Tenha orgulho pelo resultado do seu trabalho, no final do dia, apensa você sabe o que você fez, e se você não se sente confortável com o que você anda fazendo, o prazer pelo seu trabalho vai ser afetado, e isto é o que eu menos desejo para você.</p>
<p><strong>Relembrando</strong></p>
<ul>
<li><p>Faça uma documentação, mínima que seja, dando contexto sobre o sistema</p>
</li>
<li><p>Ajude você e os outros com o processo de build e up do sistema no ambiente local.</p>
</li>
<li><p>Escreva testes, tá com preguiça de fazer unitário, faça de integração então, mas faça!</p>
</li>
</ul>
<p>Ahhhh mas só isso não é nem o mínimo para ter um sistema top do top!. Calma dev sênior ultra mega foda das galaxias… para quem não tem nada o mínimo já é mais que d+. 😉</p>
<hr />
<h1 id="heading-referencias">Referências</h1>
<ul>
<li><p><a target="_blank" href="https://www.gnu.org/software/bash/">https://www.gnu.org/software/bash/</a></p>
</li>
<li><p><a target="_blank" href="https://www.gnu.org/software/make/manual/make.html">https://www.gnu.org/software/make/manual/make.html</a></p>
</li>
<li><p><a target="_blank" href="https://developers.google.com/style">https://developers.google.com/style</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/style-guide/welcome/">https://learn.microsoft.com/en-us/style-guide/welcome/</a></p>
</li>
<li><p><a target="_blank" href="https://tldp.org/">https://tldp.org/</a></p>
</li>
<li><p><a target="_blank" href="https://www.oracle.com/technical-resources/articles/java/javadoc-tool.html">https://www.oracle.com/technical-resources/articles/java/javadoc-tool.html</a></p>
</li>
<li><p><strong>Tests:</strong></p>
<ul>
<li><p>JavaScript:</p>
<ul>
<li><p><a target="_blank" href="https://medium.com/easy-coding/write-test-cases-in-javascript-5c4ede800841">https://medium.com/easy-coding/write-test-cases-in-javascript-5c4ede800841</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/how-to-start-unit-testing-javascript/">https://www.freecodecamp.org/news/how-to-start-unit-testing-javascript/</a></p>
</li>
</ul>
</li>
<li><p>Java</p>
<ul>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/java-unit-testing/">https://www.freecodecamp.org/news/java-unit-testing/</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/gervg/step-by-step-introduction-to-unit-testing-in-java-3ae7">https://dev.to/gervg/step-by-step-introduction-to-unit-testing-in-java-3ae7</a></p>
</li>
</ul>
</li>
<li><p>GO</p>
<ul>
<li><a target="_blank" href="https://go.dev/doc/tutorial/add-a-test">https://go.dev/doc/tutorial/add-a-test</a></li>
</ul>
</li>
</ul>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Ei... ECDSA? bora!?]]></title><description><![CDATA[Ok, ok, este é meu primeiro artigo, então… pega leve comigo 🙏.

Neste ano de 2024, precisei lidar com algo muito incrível chamado ECDSA, e o melhor… eu não fazia ideia do que se tratava (não que eu domine completamente hoje, mas… já sei o suficiente...]]></description><link>https://blog.maicol.dev/ei-ecdsa-bora</link><guid isPermaLink="true">https://blog.maicol.dev/ei-ecdsa-bora</guid><category><![CDATA[ECDSA]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[keccak256]]></category><category><![CDATA[secp256k1]]></category><dc:creator><![CDATA[Maicol Kaiser]]></dc:creator><pubDate>Sat, 02 Nov 2024 21:46:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731122757159/38042a2d-8249-4d74-8da0-d9a69b56b70d.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ok, ok, este é meu primeiro artigo, então… pega leve comigo 🙏.</p>
<hr />
<p>Neste ano de 2024, precisei lidar com algo muito incrível chamado ECDSA, e o melhor… eu não fazia ideia do que se tratava (<code>não que eu domine completamente hoje, mas… já sei o suficiente para escrever este artigo</code>), e… aposto que você também não, então bora comigo e vamos ver o poder dessa tecnologia 😜.</p>
<h1 id="heading-o-que-e-ecdsa">O que é ECDSA?</h1>
<p>Bom, se a gente simplesmente partir para a definição de cada letrinha, significa (Elliptic Curve Digital Signature Algorithm), em bom portugues seria algo como → “Um monte de código que usa matematica pra assinar coisas".</p>
<p>De forma prática, o ECDSA permite que uma pessoa prove que é proprietaria de uma chave privada sem revelar a chave, assinando digitalmente um conteúdo que outras pessoas possam verificar usando a chave pública.</p>
<p>Este algoritmo se encaixa muito bem em:</p>
<ul>
<li><p>Blockchain e Criptomoedas</p>
</li>
<li><p>Segurança de Redes</p>
</li>
<li><p>Assinaturas Digitais</p>
</li>
</ul>
<p>Já ouviu falar em curva eliptica? pois então, eu até pouco tempo atrás também não, se segura que a gente vai dar uma longa volta… E… só pra reforçar… relaxa, se você conseguir chegar até o final, tenho certeza que você vai me agradecer.</p>
<hr />
<h2 id="heading-o-que-e-curva-eliptica-e-porque-eu-preciso-delas">O que é curva eliptica e porque eu preciso delas?</h2>
<p>Curvas elípticas nos ajudam a definir uma espécie de caminho de mão única, onde é fácil realizar certas operações matemáticas, mas extremamente difícil revertê-las.</p>
<p>Em uma curva elíptica, é fácil multiplicar um ponto específico várias vezes para obter um novo ponto, mas é extremamente difícil descobrir quantas vezes a multiplicação foi feita para chegar naquele ponto resultante. Esse problema de encontrar o número de multiplicações necessárias é conhecido como o problema do logaritmo discreto e é o fundamento da segurança na criptografia de curvas elípticas(dá uma olhada nas referências depois).</p>
<hr />
<h3 id="heading-qual-a-aparencia-do-monstro">Qual a aparência do monstro? 🤔</h3>
<p>$$y 2 =x 3 +ax+b$$</p><h3 id="heading-bora-entender">Bora entender 🧐</h3>
<p>Primeiramente a e b → são constantes que determinam a forma específica da curva (mais sobre formas de curva nas referências).</p>
<p>Cada combinação gera uma curva diferente e elas tem uma caracteristica interessante, onde os pontos da curva podem ser adicionados de forma unica para formar novos pontos. Usando o Desmos você consegue visualizar o que eu estou tentando dizer.</p>
<p>O X da equação, é relacionado a posição horizontal de um ponto na curva. Digamos que temos uma curva onde a = 2 e b = 3 então a equação ficaria</p>
<p>$$y 2 =x 3 +2x+3$$</p><p>Ok, mas… e se a gente escolher o valor do X? por exemplo… 1</p>
<p>$$y^2 = 1^ 3 + 2 . 1 +3$$</p><p>Podemos dizer que…</p>
<p>$$y 2 = 1 + 2 + 3 = 6$$</p><p>Doido né? chegamos no valor do Y definindo a forma da curva através das constantes A e B, e a posição de um ponto horizontal na curva através do x.</p>
<p>$$y^2 = ± \sqrt{6} ≈ ±2.449$$</p><p>Dai chegamos na conclusão que os pontos <code>(1, 2.449) e (1, -2.449)</code> são validos na curva.</p>
<p>Se a gente pegar um ponto inicial e for dando novos saltos, teremos algo semelhante a isto:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730736919056/39eef32e-9b8c-401d-b40c-d75bdbe20aa9.png" alt class="image--center mx-auto" /></p>
<p><strong>Primeiro gráfico:</strong></p>
<ul>
<li><p>a = 2 e b = 3</p>
</li>
<li><p>Os pontos P em azul e o Q em laranja</p>
</li>
<li><p>Estes são os pontos iniciais. Vamos usar eles nas proximas operações.</p>
</li>
</ul>
<p><strong>Segundo gráfico:</strong></p>
<ul>
<li><p>Usa o P e o Q gerado anteiormente</p>
</li>
<li><p>A soma dos pontos P + Q resulta no novo ponto, que chamamos de R</p>
</li>
</ul>
<p><strong>Terceiro gráfico:</strong></p>
<ul>
<li>Usamos a duplicação de pontos para que através da tangente que cruza a curva, acabamos chegando em outro ponto, chamado de 2P.</li>
</ul>
<p>Espero que as ilustrações acima, tenham ajudado a entender como os pontos se relacionam. Acabamos usando a adição e duplicidade de pontos na curva.</p>
<p>Essas operações são a base de como o ECDSA funciona. No ECDSA, multiplicamos um ponto inicial na curva várias vezes para gerar uma chave pública segura, e a posição resultante no "caminho" da curva é usada como parte do processo de assinatura digital.</p>
<p>Cada ponto ( 𝑥 , 𝑦 ) na curva tem um papel específico. Ao multiplicar um ponto várias vezes, obtemos novos pontos, mas descobrir o número de multiplicações necessárias para chegar a um ponto específico é extremamente difícil — e essa dificuldade é o que torna o ECDSA seguro.</p>
<hr />
<h3 id="heading-e-eu-sou-responsavel-por-definir-estes-valores">E eu sou responsável por definir estes valores?</h3>
<p>Tá perdidinho né… eu também estava, relaxa que só piora, mas já adiantando, NÃO!</p>
<p>Existem alguns tipos de curvas padrão, como:</p>
<ul>
<li><p><code>ecp256k1</code>→ usado em blockchain</p>
</li>
<li><p><code>secp256r1</code> → usado nos protocolos TLS e SSL</p>
</li>
<li><p><code>secp384r1</code> → criptografar chaves públicas para segurança a longo prazo com alto nível de segurança, também TLS, SSL e SSH .</p>
</li>
</ul>
<p>Estas curvas já tem seus valores previamente definidos. O pessoal do SECG (Standards for Efficient Cryptography Group) e NIST (National Institute of Standards and Technology) já cuidou disso pra gente, os valores, garantem segurança e compatibilidade, então apesar de saber que existe, não precisamos nos preocupar com isto 😜👌(nas referências temos mais detalhes)</p>
<hr />
<h3 id="heading-chega-de-teoriaaaaaa">Chega de Teoriaaaaaa 😣🤯</h3>
<p>Sobreviveu? tá com pique? então vamo dale!</p>
<h3 id="heading-gerando-o-par-de-chaves">Gerando o par de chaves</h3>
<p>Vamos utilizar o <code>openssl</code> que é uma ferramenta para geração de chaves. Esta chave gerada é compativel com ECDSA.</p>
<p>Lembra da curva <code>secp256k1</code>? é aqui que ela brilha ✨</p>
<p>Podemos gerar o par em conjunto</p>
<pre><code class="lang-bash">openssl ecparam -name secp256k1 -genkey -noout -out secp256k1_key.pem
</code></pre>
<p>E extrair o par de chaves publica e privada de uma única vez</p>
<pre><code class="lang-bash">openssl ec -<span class="hljs-keyword">in</span> secp256k1_key.pem -noout -text
</code></pre>
<p>****** OUUUU *******</p>
<p>Podemos gerar apenas a chave privada</p>
<pre><code class="lang-bash">openssl ecparam -name secp256k1 -genkey -noout -out private_key.pem
</code></pre>
<p>Extraimos a chave pública baseado na chave privada gerada</p>
<pre><code class="lang-bash">openssl ec -<span class="hljs-keyword">in</span> private_key.pem -pubout -out public_key.pem
</code></pre>
<p>Precisamos da chave pública em formato Hexadecimal não compactado para realizar as assinaturas, podemos gerar ela da chave publica ou diretamente da chave privada, abaixo vou deixar as duas abordagens.</p>
<pre><code class="lang-bash"><span class="hljs-comment">### Extraindo da chave pública</span>
openssl ec -pubin -<span class="hljs-keyword">in</span> public_key.pem -outform DER -out public_key.der
tail -c 65 public_key.der | xxd -p -c 65

<span class="hljs-comment">### Extraindo da chave privada</span>
openssl ec -<span class="hljs-keyword">in</span> private_key.pem -pubout -outform DER | tail -c 65 | xxd -p -c 65
</code></pre>
<p>A chave vai iniciar com <code>0x04</code> ou <code>04</code>, que significa que não está compactada, e depois temos a sequencia de 32 bytes para cada uma das coordenadas x e y da chave pública em hexadecial total de 64 bytes.</p>
<pre><code class="lang-bash"><span class="hljs-comment">### Chave completa</span>
<span class="hljs-built_in">echo</span> -e <span class="hljs-string">"### Chave completa\n"</span><span class="hljs-string">"04eb59103e1bf87fc458f0cd188c51f1a872beae04\
e4df620d47e7282e8afee09fa5ef139bc781bfc42538f59dcc42e01e5d7e49f531d22e635\
0dfa70ea23cb040"</span>

<span class="hljs-comment">### Em partes</span>

<span class="hljs-comment">## 2 caracteres</span>
04

<span class="hljs-comment">## 64 caracteres</span>
eb59103e1bf87fc458f0cd188c51f1a872beae04e4df620d47e7282e8afee09f

<span class="hljs-comment">## 64 caracteres</span>
a5ef139bc781bfc42538f59dcc42e01e5d7e49f531d22e6350dfa70ea23cb040
</code></pre>
<h3 id="heading-devirando-o-endereco-ethereum-das-chaves">Devirando o endereço ethereum das chaves</h3>
<p>Agora que conseguimos chegar na chave pública não compactada em formato hexa, conseguimos derivar desta chave um endereço ethereum, que basicamente define de forma pública uma referência de quem é o proprietário da chave.</p>
<p>Para isso vamos precisar de mais uma nome estranho, <code>Keccak-256</code>, esse rapaz é uma função de hash criptográfica que consegue gerar o hash que será utilizado para definir o endereço ethereum.</p>
<p>Existe uma receita definida pelos desenvolvedores do ethereum (olha as referências 😉)</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Hash inteiro</span>
118a5195281508ca5ab70437c8496f9c8b1922627a4597bb9702b7ad7a9ac55c
</code></pre>
<p>O endereço é obtido a partir dos últimos 20 bytes do hash Keccak-256 da chave pública sem o prefixo <code>0x04</code>.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># ultimos 20 bytes</span>
c8496f9c8b1922627a4597bb9702b7ad7a9ac55c
</code></pre>
<p>Estes 20 bytes ou 160 bits que recuperamos, representam o endereço ethereum no formato hexadecimal e tem 40 caracteres. Ainda precisamos adicionar o prefixo <code>0x</code> como uma ceraja no bolo 🍰.</p>
<pre><code class="lang-bash"><span class="hljs-comment">### Endereço ethereum</span>
0xc8496f9c8b1922627a4597bb9702b7ad7a9ac55c
</code></pre>
<p>Acha que acabou? peraí que tem mais uma ultima coisinha.</p>
<p>Foi introduzida uma etapa no processo para garantir que o endereço fique ainda mais seguro, usando um checksum, aplicando o keccak-256 ao endereço após ser convertido para maiúsculo baseado em algumas regras. Nas referências você vai encontrar o link para o EIP-55 Ethereum Improvement Proposal (EIP).</p>
<pre><code class="lang-bash"><span class="hljs-comment">### Endereço final com o EIP-55 aplicado \0/</span>
0xc8496F9C8B1922627A4597bb9702b7ad7A9AC55C
</code></pre>
<p>Abaixo disponibilizei alguns exemplos de código 😉</p>
<p><strong>Javascript</strong></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/vakaman/pen/yLmEGwv">https://codepen.io/vakaman/pen/yLmEGwv</a></div>
<p> </p>
<p><strong>Python</strong></p>
<p>Para conseguir ver as rotas, onde eu mostro o funcionamento dos recursos, você vai precisar clicar no Ports e então localizar a porta 5000, depois só clicar no icone que diz Preview in editor e escolher a rota `Calculate Address` (talvez exista uma forma de fazer isso automaticamente, mas eu não achei como… então… me ajuda ai!)</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codesandbox.io/s/ecdsa-python-3fydf3?embed=1&amp;file=%2FREADME.md&amp;showConsole=true">https://codesandbox.io/s/ecdsa-python-3fydf3?embed=1&amp;file=%2FREADME.md&amp;showConsole=true</a></div>
<p> </p>
<hr />
<h3 id="heading-assinando-uma-mensagem">Assinando uma mensagem</h3>
<p>Legal extrair o endereço ethereum né?… até então você deve tá pensando, onde esse maluco quer chegar com isso? E eu digo… calma, agora que a brincadeira fica interessante. Vamos usar a chave privada para realizar a assinatura de uma mensagem, se liga só!</p>
<p>No exemplo, vamos assinar a seguinte mensagem</p>
<pre><code class="lang-python">    message = {
        <span class="hljs-string">"nome"</span>: <span class="hljs-string">"Maicol Oliveira"</span>,
        <span class="hljs-string">"idade"</span>: <span class="hljs-number">34</span>,
        <span class="hljs-string">"profissao"</span>: <span class="hljs-string">"Desenvolvedor"</span>
    }
</code></pre>
<p>Consumindo a rota → sign_message, vamos ter o retorno da assinatura</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"assinatura"</span>: <span class="hljs-string">"b9092c7341aaac850c6209a800a0761d9333eb02e765461fd061137ee1bb259e0d90fe911ca5aa0e201e7d512d68d0dba97654d8dd0d0e9588449e9c659cc591"</span>
}
</code></pre>
<p>Agora vamos validar esta assinatura, na rota → validate_signature_route, com a nossa chave privada, a mesma que usamos para assinar 😉</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"assinatura"</span>: <span class="hljs-string">"0x155f92d8c68a6741d4074b40d021bdc6e148aabb37ce43f8ce33d3720441c22d7405f748267537fa1ba683bc671e481d229f164a4f79e39bee5febade5861d9d"</span>,
  <span class="hljs-attr">"is_valid"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">"message"</span>: {
    <span class="hljs-attr">"idade"</span>: <span class="hljs-number">34</span>,
    <span class="hljs-attr">"nome"</span>: <span class="hljs-string">"Maicol Oliveira"</span>,
    <span class="hljs-attr">"profissao"</span>: <span class="hljs-string">"Desenvolvedor"</span>
  }
}
</code></pre>
<p>BINGO!!! a assinatura é válida, incrível não é mesmo?  </p>
<p>🧐🧐🧐🧐 Tá e… o que eu faço com isso?</p>
<p>Sei lá mano… te mostrei a ferramenta, boa sorte em onde você vai aplicar!🫠😂😅</p>
<p>Código de referência aqui</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codesandbox.io/s/ecdsa-python-3fydf3?embed=1&amp;file=%2FREADME.md&amp;showConsole=true">https://codesandbox.io/s/ecdsa-python-3fydf3?embed=1&amp;file=%2FREADME.md&amp;showConsole=true</a></div>
<p> </p>
<hr />
<h1 id="heading-historinha-para-ajudar">Historinha para ajudar…</h1>
<p>Tá.. blz, senta que lá vem a história, vamos fazer uma analogia, e depois… você que decide onde vai usar ok?  </p>
<p>Imagine que você quer enviar uma mensagem secreta para seu amigo, mas precisa que alguém a transporte para você, e essa pessoa não pode descobrir o conteúdo e também não pode alterálo.</p>
<p>Como Proteger o Segredo? 🤔</p>
<p>Simples! coloque um “selo especial” 📩:</p>
<ul>
<li><p>Você coloca sua mensagem em um envelope e usa este “selo especial” para fechá-lo. Esse selo é algo que só você sabe fazer – é único e impossível de replicar. O transportador pode ver o envelope, mas ele não consegue abrir sem estragar o selo.</p>
</li>
<li><p>Seu amigo conhece o selo. Assim, quando ele recebe o envelope e vê o selo intacto, ele sabe que:</p>
<ul>
<li><p>A mensagem de fato veio de você</p>
</li>
<li><p>Ninguém abriu ou alterou o conteúdo no caminho</p>
</li>
</ul>
</li>
</ul>
<p>O Transportador Não Pode Interferir:</p>
<ul>
<li>Quem transporta o envelope pode ver que ele tem seu selo, mas não tem como abrir e selar o envelope de novo da mesma forma.</li>
</ul>
<p>Com isso entendemos que o suposto “selo especial” é a assinatura digital, o segreto que cria o selo é a sua chave privada, o amigo que verifica o selo é a chave pública, o conteúdo da mensagem ou o segredo que ela tem é o conteúdo, seja ele um texto ou um documento e o transportador é o canal de comunicação que pode ser a internet ou outro meio de transporte dessas informações.</p>
<hr />
<h1 id="heading-conclusao">Conclusão</h1>
<p>Enfim… chegamos ao final, espero de coração que eu tenha ajudado. Tentei trazer de uma forma leve e mais didatica possível. Ficaria muito feliz com seu ponto de vista sobre o meu primeiro artigo e deixo completamente aberto o canal para feedback.</p>
<hr />
<h1 id="heading-referencias"><strong>Referências</strong></h1>
<ul>
<li><p>Vai fundo irmão…</p>
<ul>
<li><p><a target="_blank" href="https://pt.khanacademy.org/math/algebra">https://pt.khanacademy.org/math/algebra</a></p>
</li>
<li><p><a target="_blank" href="https://pt.khanacademy.org/computing/computer-science/cryptography/modern-crypt/v/discrete-logarithm-problem">https://pt.khanacademy.org/computing/computer-science/cryptography/modern-crypt/v/discrete-logarithm-problem</a></p>
</li>
<li><p><a target="_blank" href="https://www.math.brown.edu/johsilve/Presentations/WyomingEllipticCurve.pdf">https://www.math.brown.edu/johsilve/Presentations/WyomingEllipticCurve.pdf</a></p>
</li>
<li><p>Representações de curvas elípticas</p>
<ul>
<li><p>Weierstrass Form: <a target="_blank" href="https://crypto.stanford.edu/pbc/notes/elliptic/weier.html">https://crypto.stanford.edu/pbc/notes/elliptic/weier.html</a></p>
</li>
<li><p>Koblitz Form: <a target="_blank" href="https://sefiks.com/2016/03/13/the-math-behind-elliptic-curves-over-binary-field/">https://sefiks.com/2016/03/13/the-math-behind-elliptic-curves-over-binary-field/</a></p>
</li>
<li><p>Edwards form: <a target="_blank" href="https://en.wikipedia.org/wiki/Edwards_curve">https://en.wikipedia.org/wiki/Edwards_curve</a></p>
</li>
</ul>
</li>
<li><p>SECG:</p>
<ul>
<li><p>secp256k1 → página 13</p>
<ul>
<li><a target="_blank" href="https://www.secg.org/sec2-v2.pdf">https://www.secg.org/sec2-v2.pdf</a></li>
</ul>
</li>
<li><p>secp256r1 → Página 14</p>
<ul>
<li><a target="_blank" href="https://www.secg.org/sec2-v2.pdf">https://www.secg.org/sec2-v2.pdf</a></li>
</ul>
</li>
<li><p><a target="_blank" href="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf">https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf</a></p>
</li>
</ul>
</li>
<li><p>NIST:</p>
<ul>
<li><p>DSS</p>
<ul>
<li><a target="_blank" href="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf">https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf</a></li>
</ul>
</li>
<li><p>Discrete Logarithm-based</p>
<ul>
<li><a target="_blank" href="https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-186.pdf">https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-186.pdf</a></li>
</ul>
</li>
<li><p>SHA-3 Standard:</p>
<ul>
<li><a target="_blank" href="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf">https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf</a></li>
</ul>
</li>
</ul>
</li>
<li><p>ANSI</p>
<ul>
<li><p>Public Key Cryptography For The Financial Services Industry</p>
<ul>
<li><a target="_blank" href="https://safecurves.cr.yp.to/grouper.ieee.org/groups/1363/private/x9-62-09-20-98.pdf">https://safecurves.cr.yp.to/grouper.ieee.org/groups/1363/private/x9-62-09-20-98.pdf</a></li>
</ul>
</li>
</ul>
</li>
<li><p>Keccak</p>
<ul>
<li><a target="_blank" href="https://keccak.team/papers.html">https://keccak.team/papers.html</a></li>
</ul>
</li>
<li><p>Ethereum</p>
<ul>
<li><p>ETHEREUM: A SECURE DECENTRALISED GENERALISED TRANSACTION LEDGER</p>
<ul>
<li><a target="_blank" href="https://ethereum.github.io/yellowpaper/paper.pdf">https://ethereum.github.io/yellowpaper/paper.pdf</a></li>
</ul>
</li>
<li><p>EIP-55</p>
<ul>
<li><p><a target="_blank" href="https://github.com/ethereum/ercs/blob/master/ERCS/erc-55.md">https://github.com/ethereum/ercs/blob/master/ERCS/erc-55.md</a></p>
</li>
<li><p><a target="_blank" href="https://eips.ethereum.org/EIPS/eip-55">https://eips.ethereum.org/EIPS/eip-55</a></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr />
<h1 id="heading-ferramentas">Ferramentas</h1>
<ul>
<li><p>Calculadora de curva elíptica: <a target="_blank" href="https://www.desmos.com/calculator/ialhd71we3?lang=pt-BR">https://www.desmos.com/calculator/ialhd71we3?lang=pt-BR</a></p>
</li>
<li><p>Gerador de chaves</p>
<ul>
<li><p>windows: <a target="_blank" href="https://www.ibm.com/docs/en/cognos-analytics/12.0.0?topic=content-generating-ssh-keys-windows">https://www.ibm.com/docs/en/cognos-analytics/12.0.0?topic=content-generating-ssh-keys-windows</a></p>
</li>
<li><p>linux:</p>
<ul>
<li><p><a target="_blank" href="https://linux.die.net/man/1/ssh-keygen">https://linux.die.net/man/1/ssh-keygen</a></p>
</li>
<li><p><a target="_blank" href="https://www.openssl.org/">https://www.openssl.org/</a></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></content:encoded></item></channel></rss>