<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ computer networking - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ computer networking - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 28 Jul 2026 17:16:24 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/computer-networking/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Implement Zero-Trust Workload Identity in Kubernetes with SPIFFE, SPIRE, and Cilium ]]>
                </title>
                <description>
                    <![CDATA[ Your network policy says: allow traffic from 10.0.1.45. Yesterday, 10.0.1.45 was your payment service. Today, after a rolling deployment, it's your logging agent. Your payment service is now at 10.0.1 ]]>
                </description>
                <link>https://www.freecodecamp.org/news/implement-zero-trust-workload-identity-in-kubernetes-with-spiffe-spire-and-cilium/</link>
                <guid isPermaLink="false">6a4d7406fde50672308c3931</guid>
                
                    <category>
                        <![CDATA[ Kubernetes ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ networking ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Destiny Erhabor ]]>
                </dc:creator>
                <pubDate>Tue, 07 Jul 2026 21:47:50 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/4e87cffb-7972-4dcd-a705-480154778907.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Your network policy says: allow traffic from <code>10.0.1.45</code>.</p>
<p>Yesterday, <code>10.0.1.45</code> was your payment service. Today, after a rolling deployment, it's your logging agent. Your payment service is now at <code>10.0.1.89</code>.</p>
<p>Kubernetes has already updated all the endpoints and service records — but your network policy has no idea. It silently allows traffic through based on an IP address that no longer belongs to the workload you intended to trust.</p>
<p>This is the workload identity problem. IP addresses aren't an identity, they're a location. And in a Kubernetes cluster, location changes constantly. Building security policy on top of IP addresses means your security posture silently degrades every time a pod is scheduled, rescheduled, or scaled.</p>
<p>The answer is cryptographic workload identity: every workload gets a certificate-backed identity that proves who it is, not where it is. Services authenticate each other using those certificates before exchanging any data. If the certificate doesn't match, the connection is refused, regardless of what IP address it came from.</p>
<p>This is what SPIFFE and SPIRE provide. And this is how Cilium enforces it using eBPF, without injecting a sidecar into every pod.</p>
<p>In this article you'll understand how the SPIFFE identity model works, deploy SPIRE to issue cryptographic identities to workloads, and use Cilium's built-in SPIRE integration to enforce mutual TLS between services without touching your application code.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li><p>Familiarity with Kubernetes RBAC and pod security — <a href="https://www.freecodecamp.org/news/how-to-secure-a-kubernetes-cluster-handbook/">this handbook</a> covers the foundations</p>
</li>
<li><p>Familiarity with TLS certificates and Kubernetes Secrets — <a href="https://www.freecodecamp.org/news/how-to-encrypt-kubernetes-traffic/">this handbook</a> covers cert-manager and certificate concepts</p>
</li>
<li><p>Helm 3 and the Cilium CLI installed</p>
</li>
<li><p>A kind cluster — you'll create a fresh one with Cilium as the CNI in this article</p>
</li>
<li><p>Patience: this is the most complex demo I've covered in this group of articles. SPIRE has more moving parts than anything else covered so far.</p>
</li>
</ul>
<p>All demo files are in the <a href="https://github.com/Caesarsage/DevOps-Cloud-Projects/tree/main/intermediate/k8/security/cilium-mtls">companion GitHub repository</a>.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-the-workload-identity-problem">The Workload Identity Problem</a></p>
</li>
<li><p><a href="#heading-how-spiffe-works">How SPIFFE Works</a></p>
<ul>
<li><p><a href="#heading-spiffe-ids-and-trust-domains">SPIFFE IDs and Trust Domains</a></p>
</li>
<li><p><a href="#heading-svids-the-cryptographic-identity-document">SVIDs: The Cryptographic Identity Document</a></p>
</li>
<li><p><a href="#heading-the-trust-bundle">The Trust Bundle</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-how-spire-works">How SPIRE Works</a></p>
<ul>
<li><p><a href="#heading-spire-server-and-spire-agent">SPIRE Server and SPIRE Agent</a></p>
</li>
<li><p><a href="#heading-node-attestation">Node Attestation</a></p>
</li>
<li><p><a href="#heading-workload-attestation">Workload Attestation</a></p>
</li>
<li><p><a href="#heading-svid-issuance-and-rotation">SVID Issuance and Rotation</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-how-cilium-implements-mutual-tls-with-spiffe">How Cilium Implements Mutual TLS with SPIFFE</a></p>
</li>
<li><p><a href="#heading-demo-1--install-cilium-with-spire-integration">Demo 1 — Install Cilium with SPIRE Integration</a></p>
<ul>
<li><p><a href="#heading-step-1-install-the-cilium-cli">Step 1: Install the Cilium CLI</a></p>
</li>
<li><p><a href="#heading-step-2-create-a-kind-cluster-without-a-default-cni">Step 2: Create a kind cluster without a default CNI</a></p>
</li>
<li><p><a href="#heading-step-3-install-cilium-with-spire-enabled">Step 3: Install Cilium with SPIRE enabled</a></p>
</li>
<li><p><a href="#heading-step-4-verify-the-installation">Step 4: Verify the installation</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-demo-2--enforce-mutual-tls-with-a-ciliumnetworkpolicy">Demo 2 — Enforce Mutual TLS with a CiliumNetworkPolicy</a></p>
<ul>
<li><p><a href="#heading-step-1-deploy-a-client-and-server">Step 1: Deploy a client and server</a></p>
</li>
<li><p><a href="#heading-step-2-confirm-traffic-flows-without-authentication">Step 2: Confirm traffic flows without authentication</a></p>
</li>
<li><p><a href="#heading-step-3-apply-a-ciliumnetworkpolicy-requiring-mutual-authentication">Step 3: Apply a CiliumNetworkPolicy requiring mutual authentication</a></p>
</li>
<li><p><a href="#heading-step-4-verify-authenticated-traffic-still-flows">Step 4: Verify authenticated traffic still flows</a></p>
</li>
<li><p><a href="#heading-step-5-observe-the-authentication-with-hubble-optional">Step 5: Observe the authentication with Hubble (optional)</a></p>
</li>
<li><p><a href="#heading-step-6-verify-that-a-pod-without-the-matching-label-is-blocked">Step 6: Verify that a pod without the matching label is blocked</a></p>
</li>
<li><p><a href="#heading-step-7-check-the-workload-entries-in-spire">Step 7: Check the workload entries in SPIRE</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
<li><p><a href="#heading-cleanup-kind">Cleanup (kind)</a></p>
</li>
</ul>
<h2 id="heading-the-workload-identity-problem">The Workload Identity Problem</h2>
<p>The opening scenario isn't theoretical. In Kubernetes, pods are ephemeral. The scheduler can place a pod on any node, and a pod's IP address is assigned at scheduling time from the node's IP pool.</p>
<p>When a pod is deleted and recreated through a rolling deployment, a node drain, or an autoscaler event, it gets a new IP address. If you've written a NetworkPolicy that says, "allow traffic from this IP", that policy is now pointing at nothing, or worse, at a different workload.</p>
<p>Kubernetes service names help here for east-west traffic — a Service name resolves consistently regardless of which pods back it. But a NetworkPolicy based on a Service name is still a label selector match, not a cryptographic assertion. Any pod that can spoof the right labels can bypass it.</p>
<p>What you actually want is this: before service A sends a request to service B, service B proves its identity cryptographically. If service B can't prove it is who it claims to be, service A refuses the connection. This is mutual TLS, and the key question is: where do the identities come from?</p>
<p>SPIFFE answers that question.</p>
<h2 id="heading-how-spiffe-works">How SPIFFE Works</h2>
<p>SPIFFE — Secure Production Identity Framework for Everyone — is a CNCF standard that defines a model for workload identity. It doesn't implement anything by itself. It specifies the format of identities, the API for requesting them, and the trust model that makes them verifiable across services, clusters, and clouds. SPIRE is the reference implementation of that specification.</p>
<h3 id="heading-spiffe-ids-and-trust-domains">SPIFFE IDs and Trust Domains</h3>
<p>A SPIFFE identity is a URI with a specific format:</p>
<pre><code class="language-plaintext">spiffe://&lt;trust-domain&gt;/&lt;workload-path&gt;
</code></pre>
<p>The trust domain is a string that identifies the administrative boundary — typically your organisation, cluster, or environment. Everything within the same trust domain can verify each other's identities. Identities from different trust domains require explicit federation configuration.</p>
<p>Some concrete examples:</p>
<pre><code class="language-plaintext">spiffe://payments.corp/ns/production/sa/checkout
spiffe://analytics.corp/ns/data/sa/pipeline-worker
spiffe://cluster.local/ns/monitoring/sa/prometheus
</code></pre>
<p>The path after the trust domain is arbitrary — it's defined by your SPIRE configuration and typically encodes the Kubernetes namespace and service account of the workload.</p>
<h3 id="heading-svids-the-cryptographic-identity-document">SVIDs: The Cryptographic Identity Document</h3>
<p>An SVID — SPIFFE Verifiable Identity Document — is how a SPIFFE identity is materialised into something a service can actually use.</p>
<p>There are two SVID formats.</p>
<p>An <strong>X.509 SVID</strong> is a standard TLS certificate where the SPIFFE ID is embedded in the Subject Alternative Name (SAN) URI field. Because it's a standard X.509 certificate, any TLS library can use it without modification.</p>
<p>The workload presents this certificate in a TLS handshake, and the peer verifies the certificate was signed by a trusted SPIRE server. This is the format used for long-lived connections like gRPC streams.</p>
<p>A <strong>JWT SVID</strong> is a signed JSON Web Token containing the SPIFFE ID as a claim. It's suitable for request-based authentication over HTTP — pass it in an Authorization header, and the receiving service verifies the signature.</p>
<p>JWT SVIDs are shorter-lived than X.509 SVIDs and scoped to a specific audience to prevent token reuse across services.</p>
<p>For Cilium's mutual authentication, X.509 SVIDs are used. The rest of this article focuses on X.509.</p>
<h3 id="heading-the-trust-bundle">The Trust Bundle</h3>
<p>For service A to verify service B's certificate, service A needs to know which Certificate Authority signed it. In SPIFFE, this is called the trust bundle — the set of CA certificates that are trusted within a trust domain.</p>
<p>SPIRE makes the trust bundle available via the Workload API. When a workload requests its identity, it also receives the current trust bundle. When the SPIRE server rotates its CA, it distributes the new trust bundle to all agents, which push it to all workloads. Your application never has to manage trust bundles manually.</p>
<h2 id="heading-how-spire-works">How SPIRE Works</h2>
<p>SPIRE is the engine that issues SVIDs and manages the identity lifecycle. Understanding its architecture is what makes the Cilium integration make sense.</p>
<h3 id="heading-spire-server-and-spire-agent">SPIRE Server and SPIRE Agent</h3>
<p>SPIRE has two main components. The <strong>SPIRE Server</strong> is the central CA. It maintains a registry of workload entries (records that describe which SPIFFE IDs should be issued to which workloads). It issues SVIDs to agents on behalf of workloads, and it's the root of trust for the entire trust domain.</p>
<p>The <strong>SPIRE Agent</strong> runs on every node as a DaemonSet. It has two jobs. First, it proves to the SPIRE Server that it's running on a legitimate node. This is called node attestation. Second, it exposes the SPIFFE Workload API on a Unix socket on the node, which workloads use to request their SVIDs.</p>
<p>The agent caches SVIDs locally so that a temporary loss of connection to the SPIRE Server doesn't immediately break workload identity.</p>
<p>This split — central server, per-node agents — is deliberate. Workloads never contact the SPIRE Server directly. They only talk to the agent on their own node. The agent mediates all identity requests, which limits the blast radius if a node is compromised.</p>
<h3 id="heading-node-attestation">Node Attestation</h3>
<p>When a SPIRE Agent starts up on a new node, it needs to prove its own identity to the SPIRE Server before it can serve identities to workloads. This is node attestation.</p>
<p>In Kubernetes, SPIRE uses <strong>PSAT</strong> — Projected Service Account Tokens — for node attestation. The agent presents a Kubernetes service account token that is projected specifically for the SPIRE server's audience. The SPIRE Server contacts the Kubernetes API to verify the token, confirms the agent is running in the expected namespace with the expected service account, and issues the agent its own SVID.</p>
<p>This is the reason SPIRE requires specific Kubernetes API flags. The kube-apiserver must be configured to support projected service account tokens with the right audience, which is why the kind cluster config in the demo below sets <code>--api-audiences</code> and <code>--service-account-issuer</code>.</p>
<h3 id="heading-workload-attestation">Workload Attestation</h3>
<p>Once a node has been attested, its agent can attest workloads. When a workload connects to the Workload API socket and requests an SVID, the agent collects facts about that workload (like its Kubernetes namespace, service account, pod name, and labels) by querying the Kubernetes API. It matches those facts against the workload entries registered in the SPIRE Server. If a matching entry exists, the agent issues the corresponding SVID.</p>
<p>A workload entry looks like this:</p>
<pre><code class="language-plaintext">SPIFFE ID: spiffe://example.org/ns/production/sa/checkout
Parent ID: spiffe://example.org/spire/agent/k8s_psat/default/&lt;node-uid&gt;
Selectors:
  k8s:ns:production
  k8s:sa:checkout
</code></pre>
<p>The selectors describe the Kubernetes facts that must match. A pod running in the <code>production</code> namespace with service account <code>checkout</code> will receive the SPIFFE ID <code>spiffe://example.org/ns/production/sa/checkout</code>. Any other pod will not.</p>
<h3 id="heading-svid-issuance-and-rotation">SVID Issuance and Rotation</h3>
<p>SVIDs are short-lived by design. The default TTL for X.509 SVIDs in SPIRE is one hour. The SPIRE Agent automatically rotates them in the background — generating a new key pair, requesting a fresh SVID from the server, and making the new SVID available on the Workload API before the old one expires.</p>
<p>Workloads that use the Workload API directly or tools like the SPIFFE CSI driver get the new SVID transparently.</p>
<p>Short-lived credentials are the zero-trust way. If a workload's SVID is compromised, it's only valid for an hour. Compare that to a Kubernetes service account token, which was historically valid forever.</p>
<h2 id="heading-how-cilium-implements-mutual-tls-with-spiffe">How Cilium Implements Mutual TLS with SPIFFE</h2>
<p>Traditional approaches to service mesh mTLS (like Istio or Linkerd) inject a sidecar proxy into every pod. The proxy intercepts all traffic and handles the TLS handshake. The application has no idea TLS is happening. The sidecar adds memory overhead (roughly 50–100MB per pod for Envoy), an extra network hop on every request, and a complex certificate injection mechanism.</p>
<p>Cilium takes a different path. Rather than injecting a proxy, it handles authentication at the network layer using eBPF. The Cilium agent running on each node intercepts connections, performs the mutual TLS handshake using SPIFFE SVIDs, and enforces the authentication result — all in the kernel, without any user-space proxy.</p>
<p>The mechanism works like this. When pod A initiates a connection to pod B, the Cilium agent on pod A's node intercepts the connection. It retrieves pod A's SVID from the SPIRE Workload API. It checks whether there's a <code>CiliumNetworkPolicy</code> requiring mutual authentication for this connection. If there is, it performs a TLS handshake with the Cilium agent on pod B's node, presenting pod A's SVID and requesting pod B's SVID in return.</p>
<p>Both agents verify the SVID against the SPIRE trust bundle. If both SVIDs are valid and the policy allows the connection, it proceeds. If either SVID is invalid or missing, the connection is dropped.</p>
<p>The application on pod A receives data from the application on pod B. Neither application wrote any TLS code. Neither has a sidecar. The authentication happened entirely in the Cilium agents on their respective nodes.</p>
<p>In Cilium's model, the Cilium agent itself gets a SPIFFE identity from SPIRE. It acts as a delegate identity that can request SVIDs on behalf of workloads.</p>
<p>This is slightly different from the standalone SPIRE model where each workload requests its own SVID directly. The Cilium operator registers workload entries in SPIRE automatically based on the Kubernetes Identities it manages, so you don't need to manually create SPIRE entries for every pod.</p>
<h2 id="heading-demo-1-install-cilium-with-spire-integration">Demo 1 — Install Cilium with SPIRE Integration</h2>
<p>You'll create a kind cluster with Cilium as the CNI and enable its built-in SPIRE integration in a single Helm command.</p>
<h3 id="heading-step-1-install-the-cilium-cli">Step 1: Install the Cilium CLI</h3>
<pre><code class="language-bash"># macOS
brew install cilium-cli

# Linux
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
curl -L --remote-name-all \
  https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-amd64.tar.gz
sudo tar -xzf cilium-linux-amd64.tar.gz -C /usr/local/bin
</code></pre>
<h3 id="heading-step-2-create-a-kind-cluster-without-a-default-cni">Step 2: Create a kind Cluster Without a Default CNI</h3>
<p>kind's default CNI (kindnet) must be disabled so Cilium can take its place. Save this as <code>kind-cilium.yaml</code>:</p>
<pre><code class="language-yaml"># kind-cilium.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
  - role: worker
  - role: worker
networking:
  disableDefaultCNI: true   # Required: let Cilium be the CNI
  kubeProxyMode: none       # Cilium replaces kube-proxy too
</code></pre>
<pre><code class="language-bash">kind create cluster --name k8s-mtls --config kind-cilium.yaml
</code></pre>
<p>The nodes will be in a <code>NotReady</code> state until Cilium is installed. This is expected because there's no CNI yet.</p>
<h3 id="heading-step-3-install-cilium-with-spire-enabled">Step 3: Install Cilium with SPIRE Enabled</h3>
<p>Because Step 2 set <code>kubeProxyMode: none</code>, Cilium has to play the kube-proxy role itself. That means its bootstrap pods can't reach the API server via the <code>kubernetes</code> Service ClusterIP, because nothing is routing it yet.</p>
<p>You have to pass the API server's real address up front. Grab the kind control-plane's IP from Docker:</p>
<pre><code class="language-bash">API_SERVER_IP=$(docker inspect k8s-mtls-control-plane \
  --format='{{ .NetworkSettings.Networks.kind.IPAddress }}')
echo "API_SERVER_IP=$API_SERVER_IP"
</code></pre>
<p>Then install Cilium with SPIRE:</p>
<pre><code class="language-bash">helm repo add cilium https://helm.cilium.io/
helm repo update

helm upgrade cilium cilium/cilium \
  --install \
  --namespace kube-system \
  --set kubeProxyReplacement=true \
  --set k8sServiceHost=${API_SERVER_IP} \
  --set k8sServicePort=6443 \
  --set authentication.enabled=true \
  --set authentication.mutual.spire.enabled=true \
  --set authentication.mutual.spire.install.enabled=true \
  --set authentication.mutual.spire.install.server.dataStorage.enabled=false
</code></pre>
<p>A few of these flags are easy to miss but each is load-bearing:</p>
<ul>
<li><p><code>kubeProxyReplacement=true</code>: Cilium installs its eBPF-based replacement for kube-proxy. Mandatory whenever the kind config sets <code>kubeProxyMode: none</code>.</p>
</li>
<li><p><code>k8sServiceHost</code> / <code>k8sServicePort</code>: direct API server address used during bootstrap, before Cilium can route the Service ClusterIP. On EKS/GKE/AKS you don't need this because kube-proxy is still present during install.</p>
</li>
<li><p><code>authentication.enabled=true</code>: required alongside <code>authentication.mutual.spire.enabled=true</code>. The chart's <code>validate.yaml</code> rejects the install with <code>SPIRE integration requires .Values.authentication.enabled=true and .Values.authentication.mutual.spire.enabled=true</code> if you set only the mutual flag.</p>
</li>
<li><p><code>dataStorage.enabled=false</code>: switches the SPIRE server from a PVC-backed datastore to in-memory. Fine for a lab cluster, but in production leave this enabled and ensure your cluster has PersistentVolume support.</p>
</li>
</ul>
<p>Notice there's no <code>--wait</code> flag here. On a fresh cluster, <code>--wait</code> will appear to fail with <code>context deadline exceeded</code> because the install is racey by design. The SPIRE server has to schedule on a <code>NotReady</code> node thanks to its tolerations, then Cilium agents come up using SPIRE, then nodes flip to <code>Ready</code>. Let the install return immediately and watch the pods come up over the next ~2 minutes:</p>
<pre><code class="language-bash">kubectl get pods -A -w
</code></pre>
<h3 id="heading-step-4-verify-the-installation">Step 4: Verify the Installation</h3>
<pre><code class="language-bash">cilium status --wait
</code></pre>
<pre><code class="language-plaintext">    /¯¯\
 /¯¯\__/¯¯\    Cilium:             OK
 \__/¯¯\__/    Operator:           OK
 /¯¯\__/¯¯\    Envoy DaemonSet:    OK
 \__/¯¯\__/    Hubble Relay:       disabled
    \__/       ClusterMesh:        disabled

DaemonSet              cilium             Desired: 3, Ready: 3/3, Available: 3/3
DaemonSet              cilium-envoy       Desired: 3, Ready: 3/3, Available: 3/3
Deployment             cilium-operator    Desired: 2, Ready: 2/2, Available: 2/2
</code></pre>
<p>Three Cilium agents, one per node, including the control-plane (no taints in the kind config). Check the SPIRE components in the <code>cilium-spire</code> namespace:</p>
<pre><code class="language-bash">kubectl get all -n cilium-spire
</code></pre>
<pre><code class="language-plaintext">NAME                    READY   STATUS    RESTARTS   AGE
pod/spire-agent-2cpsr   1/1     Running   0          3m
pod/spire-agent-klhjx   1/1     Running   0          3m
pod/spire-agent-vhsnc   1/1     Running   0          3m
pod/spire-server-0      2/2     Running   0          3m

NAME                              TYPE        CLUSTER-IP    PORT(S)    AGE
service/spire-server              ClusterIP   10.96.x.x     8081/TCP   3m

NAME                          DESIRED   CURRENT   READY   AGE
daemonset.apps/spire-agent    3         3         3       3m

NAME                             READY   AGE
statefulset.apps/spire-server    1/1     3m
</code></pre>
<p>One SPIRE agent per node. The SPIRE server is a StatefulSet with two containers: the server itself plus the SPIRE controller manager, which automatically creates workload registration entries for Cilium identities.</p>
<p>Run a health check on the SPIRE server:</p>
<pre><code class="language-bash">kubectl exec -n cilium-spire spire-server-0 -c spire-server -- \
  /opt/spire/bin/spire-server healthcheck
</code></pre>
<pre><code class="language-plaintext">Server is healthy.
</code></pre>
<p>Verify the SPIRE agents have been attested:</p>
<pre><code class="language-bash">kubectl exec -n cilium-spire spire-server-0 -c spire-server -- \
  /opt/spire/bin/spire-server agent list
</code></pre>
<pre><code class="language-plaintext">Found 3 attested agents:

SPIFFE ID         : spiffe://spiffe.cilium/spire/agent/k8s_psat/default/&lt;node-uid-1&gt;
Attestation type  : k8s_psat
Expiration time   : 2026-05-17 21:08:47 +0000 UTC
Serial number     : 91532884191503307904684123063465502141
Can re-attest     : true

SPIFFE ID         : spiffe://spiffe.cilium/spire/agent/k8s_psat/default/&lt;node-uid-2&gt;
...
</code></pre>
<p>Three agents, one per node, all attested via Kubernetes PSAT. The SPIRE server trusts every node and will issue SVIDs to workloads running on them.</p>
<p>At this point the identity platform is fully in place, but nothing is using it yet. Demo 1 built the machinery that <em>issues</em> cryptographic identities. Demo 2, which we'll walk through next, puts that machinery to work, turning those SVIDs into an enforced mutual-TLS policy between two real services. Keep the cluster from Demo 1 running, as Demo 2 builds directly on it.</p>
<h2 id="heading-demo-2-enforce-mutual-tls-with-a-ciliumnetworkpolicy">Demo 2 — Enforce Mutual TLS with a CiliumNetworkPolicy</h2>
<p>Picking up in the same cluster from Demo 1, you'll deploy two services, enforce mutual authentication between them with a <code>CiliumNetworkPolicy</code>, verify that authenticated traffic flows, and confirm that unauthenticated connections are blocked.</p>
<p>Every request here is authenticated with the SVIDs that the SPIRE server you just verified hands out. These two demos are one continuous walkthrough, not standalone exercises.</p>
<h3 id="heading-step-1-deploy-a-client-and-server">Step 1: Deploy a Client and Server</h3>
<p>This file contains both the server and the client — the client is a sleeping curl pod we'll use to exec into.</p>
<pre><code class="language-yaml"># echo-workloads.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo-server
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: echo-server
  template:
    metadata:
      labels:
        app: echo-server
    spec:
      containers:
        - name: echo-server
          image: ealen/echo-server:latest
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: echo-server
  namespace: default
spec:
  selector:
    app: echo-server
  ports:
    - port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo-client
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: echo-client
  template:
    metadata:
      labels:
        app: echo-client
    spec:
      containers:
        - name: client
          image: curlimages/curl:latest
          command: ["sleep", "infinity"]
</code></pre>
<pre><code class="language-bash">kubectl apply -f echo-workloads.yaml
# kubectl rollout status only takes one resource at a time
kubectl rollout status deployment/echo-server -n default
kubectl rollout status deployment/echo-client -n default
</code></pre>
<h3 id="heading-step-2-confirm-traffic-flows-without-authentication">Step 2: Confirm Traffic Flows Without Authentication</h3>
<p>Before enforcing mTLS, confirm the client can reach the server:</p>
<pre><code class="language-bash">CLIENT=$(kubectl get pod -l app=echo-client -o jsonpath='{.items[0].metadata.name}')
kubectl exec $CLIENT -- curl -s http://echo-server/
</code></pre>
<p>You should get a JSON response from the echo server. Traffic flows freely with no authentication.</p>
<h3 id="heading-step-3-apply-a-ciliumnetworkpolicy-requiring-mutual-authentication">Step 3: Apply a CiliumNetworkPolicy Requiring Mutual Authentication</h3>
<p>Adding <code>authentication.mode: required</code> to a <code>CiliumNetworkPolicy</code> tells Cilium to enforce mutual TLS for matching traffic. Both sides of the connection must present a valid SPIFFE SVID:</p>
<pre><code class="language-yaml"># mtls-policy.yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: echo-server-mtls
  namespace: default
spec:
  endpointSelector:
    matchLabels:
      app: echo-server
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: echo-client
      authentication:
        mode: required     # Require mutual TLS for this traffic
</code></pre>
<pre><code class="language-bash">kubectl apply -f mtls-policy.yaml
</code></pre>
<h3 id="heading-step-4-verify-authenticated-traffic-still-flows">Step 4: Verify Authenticated Traffic Still Flows</h3>
<pre><code class="language-bash">kubectl exec $CLIENT -- curl -s http://echo-server/
</code></pre>
<p>The connection succeeds. Cilium intercepted it, performed the SPIFFE mTLS handshake between the Cilium agents on both pods' nodes, verified both SVIDs, and allowed the traffic through. The application on the client sent a plain HTTP request and received a response — the mutual authentication happened transparently at the network layer.</p>
<h3 id="heading-step-5-observe-the-authentication-with-hubble-optional">Step 5: Observe the Authentication with Hubble (Optional)</h3>
<p>Hubble is Cilium's observability layer. It needs its own CLI:</p>
<pre><code class="language-bash"># macOS
brew install hubble

# Linux
HUBBLE_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/hubble/master/stable.txt)
curl -L --remote-name-all \
  https://github.com/cilium/hubble/releases/download/${HUBBLE_VERSION}/hubble-linux-amd64.tar.gz
sudo tar -xzf hubble-linux-amd64.tar.gz -C /usr/local/bin
</code></pre>
<p>Enable Hubble in the cluster, then watch flows. <code>cilium hubble enable</code> deploys Hubble Relay <em>and</em> restarts the Cilium agents to switch on the Hubble server inside them, so wait for it to settle before port-forwarding. If you skip the wait, the port-forward connects before Relay is listening, then dies with <code>connection reset by peer</code> / <code>rpc error … EOF</code>:</p>
<pre><code class="language-bash">cilium hubble enable
cilium status --wait          # wait for "Hubble Relay: OK" before continuing

cilium hubble port-forward &amp;

# Watch flows for the echo-server (Ctrl-C to stop)
hubble observe --namespace default --pod echo-server --follow
</code></pre>
<p>Trigger another request in a second terminal:</p>
<pre><code class="language-bash">kubectl exec $CLIENT -- curl -s http://echo-server/
</code></pre>
<p>In the Hubble output you'll see:</p>
<pre><code class="language-plaintext">
ℹ️  Hubble Relay is available at 127.0.0.1:4245
Jul  7 12:44:42.380: default/echo-client-86d446b8f-9bn5v:47500 (ID:2822) -&gt; default/echo-server-7467b4b54d-5tvkz:80 (ID:30854) policy-verdict:none TRAFFIC_DIRECTION_UNKNOWN ALLOWED (TCP Flags: SYN)
Jul  7 12:44:42.380: default/echo-client-86d446b8f-9bn5v:47500 (ID:2822) -&gt; default/echo-server-7467b4b54d-5tvkz:80 (ID:30854) to-endpoint FORWARDED (TCP Flags: SYN)
Jul  7 12:44:42.381: default/echo-client-86d446b8f-9bn5v:47500 (ID:2822) &lt;- default/echo-server-7467b4b54d-5tvkz:80 (ID:30854) to-endpoint FORWARDED (TCP Flags: SYN, ACK)
</code></pre>
<p>The <code>ALLOWED</code> verdict with the <code>policy-verdict</code> reason confirms the CiliumNetworkPolicy matched and authentication was verified. No sidecar involved — this happened in the Cilium agents.</p>
<p><strong>Prefer a graphical view? Enable the Hubble UI.</strong> Everything above is the API + terminal path (Relay on port 4245 backs the <code>hubble</code> CLI). Hubble also ships a web dashboard with a live service map — but it's a separate component that <code>cilium hubble enable</code> does <em>not</em> start by default:</p>
<pre><code class="language-bash"># Add the UI (re-runs enable, keeps Relay, adds the hubble-ui deployment)
cilium hubble enable --ui

# Wait for it to be Ready before opening — same race as Relay. Skip this and
# `cilium hubble ui` fails with "connection refused" on port 8081, because the
# UI's frontend container isn't listening yet.
kubectl -n kube-system rollout status deployment/hubble-ui --timeout=90s

# Port-forwards hubble-ui and opens http://localhost:12000 in your browser
cilium hubble ui
</code></pre>
<p>Select the <code>default</code> namespace from the dropdown. That's where the demo pods and the policy live. The map is <em>live</em>: it renders edges from flows as they happen, so an idle namespace looks empty. Trigger a request to light it up:</p>
<pre><code class="language-bash">kubectl exec $CLIENT -- curl -s http://echo-server/
</code></pre>
<p>You'll see a forwarded edge <code>echo-client → echo-server</code>. Click it (or open the flow table at the bottom) to read the <code>policy-verdict: ALLOWED</code>. Leave the UI open through Step 6. When you run the unauthorized-client test there, its connection shows up as a red <em>dropped</em> edge, the visual counterpart to the <code>curl</code> timeout.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5f2a6b76d7d55f162b5da2ee/ee0f0824-74e1-4282-82e8-fcf5a9c06835.png" alt="Hubble UI — live service map for the  namespace, with forwarded and dropped flows" style="display:block;margin:0 auto" width="1672" height="986" loading="lazy">

<p>The UI has three parts.</p>
<p>The <strong>service map</strong> at the top draws each workload identity as a box and each observed connection as an edge colored by verdict: <code>echo-client → echo-server:80</code> is a solid green (forwarded) edge, while the box labelled <code>default</code> (that's the <code>unauthorized</code> pod, which carries only the namespace identity because it has no <code>app</code> label, so Hubble names it after that) reaches <code>echo-server</code> over a red dashed (dropped) line. The 🔒 lock on <code>echo-server</code>'s <code>→ 80 TCP</code> port marks that endpoint as mutually authenticated by the policy.</p>
<p>The <strong>flow table</strong> underneath logs one row per flow: source identity, destination identity, destination port, L7 info, <code>Verdict</code>, and timestamp. This lets you read both outcomes side by side, with <code>echo-client → echo-server</code> rows marked <strong>forwarded</strong> and <code>default → echo-server</code> rows marked <strong>dropped</strong>. This is the same allow/deny split as the CLI, one line per packet.</p>
<p>The <strong>top bar</strong> holds the namespace selector, a flow filter, the <code>Any verdict</code> / <code>Visual</code> toggle, and a live <code>flows/s</code> rate alongside the count of reporting nodes (<code>3/3</code>).</p>
<h3 id="heading-step-6-verify-that-a-pod-without-the-matching-label-is-blocked">Step 6: Verify That a Pod Without the Matching Label is Blocked</h3>
<p>Deploy a third pod without the <code>echo-client</code> label and try to reach the server:</p>
<pre><code class="language-yaml"># unauthorized-client.yaml
apiVersion: v1
kind: Pod
metadata:
  name: unauthorized
  namespace: default
spec:
  containers:
    - name: client
      image: curlimages/curl:latest
      command: ["sleep", "infinity"]
</code></pre>
<pre><code class="language-bash">kubectl apply -f unauthorized-client.yaml
kubectl wait --for=condition=Ready pod/unauthorized --timeout=60s
kubectl exec unauthorized -- curl -sS --max-time 5 http://echo-server/
</code></pre>
<pre><code class="language-plaintext">curl: (28) Connection timed out after 5000 milliseconds
</code></pre>
<p>The connection times out. The <code>CiliumNetworkPolicy</code> only permits ingress from pods with <code>app: echo-client</code>. A pod without that label gets no SVID match and no policy match. Cilium drops the traffic silently.</p>
<p>There are two gotchas to watch out for here. Run <code>kubectl wait</code> before exec. Run exec too soon after <code>apply</code> and you get <code>container not found ("client")</code> because the pod's container hasn't started yet.</p>
<p>And use <code>curl -sS</code>, not plain <code>-s</code>. With only <code>-s</code>, curl swallows the error text and you just see <code>command terminated with exit code 28</code>. That's the same result — 28 <em>is</em> curl's timeout code — but the <code>-S</code> restores the readable message. The fact that it times out (rather than "connection refused") is the signature of a policy <em>drop</em>: the packets are silently blackholed, not actively rejected. A refusal would return instantly with a different error.</p>
<h3 id="heading-step-7-check-the-workload-entries-in-spire">Step 7: Check the Workload Entries in SPIRE</h3>
<p>Cilium's SPIRE controller manager automatically created SPIFFE identities for the Cilium security identities in this cluster. You can see them:</p>
<pre><code class="language-bash">kubectl exec -n cilium-spire spire-server-0 -c spire-server -- \
  /opt/spire/bin/spire-server entry show \
  -selector cilium:mutual-auth
</code></pre>
<p>Each entry maps a Cilium security identity to a SPIFFE ID. The Cilium operator manages this registry automatically, so you never need to register workloads manually when using Cilium's built-in integration.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>IP addresses are location, not identity. And in Kubernetes, location changes with every deployment, so any policy built on address matching silently degrades over time.</p>
<p>Cryptographic workload identity fixes that at the foundation. SPIFFE defines the model (a SPIFFE ID names a workload within a trust domain, an X.509 SVID materialises it into a certificate any TLS library can verify), and SPIRE implements it: the server is the CA and registry, while per-node agents attest via Kubernetes PSAT and issue short-lived, auto-rotating SVIDs.</p>
<p>Cilium wires that identity layer into the network. Add <code>authentication.mode: required</code> to a CiliumNetworkPolicy and its eBPF agents fetch both workloads' SVIDs, run the mutual TLS handshake, and enforce the verdict. There's no sidecar, no application changes, and near-zero overhead versus a service mesh. And you deployed the whole stack in a single Helm command: the complexity lives in the infrastructure, not in your code.</p>
<h2 id="heading-cleanup-kind">Cleanup (kind)</h2>
<pre><code class="language-bash"># Delete demo workloads
kubectl delete deployment echo-server echo-client -n default
kubectl delete service echo-server -n default
kubectl delete pod unauthorized -n default
kubectl delete ciliumnetworkpolicy echo-server-mtls -n default

# Uninstall Cilium (helm doesn't delete the cilium-spire namespace it created)
helm uninstall cilium -n kube-system
kubectl delete namespace cilium-spire

# Delete the cluster (easiest reset on kind)
kind delete cluster --name k8s-mtls
</code></pre>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The Best Cloudflare Tunnel Alternatives – How to Choose the Right Tunneling Solution for Your Use Case ]]>
                </title>
                <description>
                    <![CDATA[ Cloudflare Tunnel is a secure tunneling solution that allows developers to expose local applications and private services to the internet without opening inbound ports or changing firewall rules. Inst ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-choose-the-right-tunneling-tool/</link>
                <guid isPermaLink="false">6a3ea9940d87116ae52e3a24</guid>
                
                    <category>
                        <![CDATA[ tunneling ]]>
                    </category>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ networking ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abdul Talha ]]>
                </dc:creator>
                <pubDate>Fri, 26 Jun 2026 16:32:20 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/3438d8ee-f43d-42ac-a4df-8ceb7b983664.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Cloudflare Tunnel is a secure tunneling solution that allows developers to expose local applications and private services to the internet without opening inbound ports or changing firewall rules.</p>
<p>Instead of accepting direct incoming traffic, Cloudflare Tunnel creates an outbound connection to Cloudflare's network and routes requests through its global edge infrastructure. This approach improves security while making services accessible from anywhere.</p>
<p>Developers commonly use Cloudflare Tunnel for exposing local applications, testing webhooks, accessing internal tools remotely, and publishing self-hosted services.</p>
<p>One of its biggest advantages is its integration with the broader Cloudflare ecosystem. Teams can combine tunnels with Cloudflare Access, DNS management, and Zero Trust security policies to create a secure access layer for their applications.</p>
<p>Cloudflare Tunnel is an excellent choice for many use cases. But some teams need features that it doesn't prioritise, such as complete infrastructure control, support for additional protocols, built-in debugging tools, or fully self-hosted, open-source solutions. Others may prefer alternatives that integrate more closely with their existing networking platforms.</p>
<p>As the tunneling ecosystem has grown, several alternatives have emerged that focus on different priorities such as developer experience, security, flexibility, and infrastructure control.</p>
<p>In this article, we'll explore five of the best Cloudflare Tunnel alternatives and help you choose the right solution for your use case.</p>
<h3 id="heading-what-well-cover">What We'll Cover:</h3>
<ol>
<li><p><a href="#heading-localxpose">LocalXpose</a></p>
</li>
<li><p><a href="#heading-tailscale-funnel">Tailscale Funnel</a></p>
</li>
<li><p><a href="#heading-inlets">Inlets</a></p>
</li>
<li><p><a href="#heading-frp-fast-reverse-proxy">FRP (Fast Reverse Proxy)</a></p>
</li>
<li><p><a href="#heading-tunnelmole">Tunnelmole</a></p>
</li>
</ol>
<h2 id="heading-1-localxpose">1. LocalXpose</h2>
<img src="https://localxpose.io/image/localxpose-product.png" alt="LocalXpose img" style="display:block;margin:0 auto" width="1200" height="630" loading="lazy">

<p><a href="https://localxpose.io/">LocalXpose</a> is a tunneling and reverse proxy solution designed for developers who need to expose local applications and services to the internet quickly. It supports multiple tunnel types, including HTTP, HTTPS, TCP, TLS, and UDP, making it suitable for a wide range of development workflows.</p>
<p>LocalXpose's standout features are traffic inspection. Developers can inspect incoming requests and replay them when testing webhooks, APIs, and third-party integrations. This makes debugging much easier compared to tools that simply forward traffic.</p>
<p>The platform also supports custom domains and multiple tunnels from a single configuration. This is useful when working with microservices or applications that require several public endpoints.</p>
<p>From a usability perspective, LocalXpose focuses on simplicity. Developers can create tunnels quickly using the CLI without dealing with complex networking configurations.</p>
<p>The drawback is that LocalXpose relies on managed relay infrastructure rather than a fully self-hosted deployment model. Teams with strict infrastructure requirements may prefer self-hosted alternatives.</p>
<p>For most developers, though, LocalXpose offers a strong balance of ease of use, protocol support, and debugging capabilities. It's an excellent choice for exposing local applications, testing webhooks, and sharing development environments.</p>
<p><strong>Pricing:</strong> LocalXpose offers a free plan for getting started, while paid plans unlock additional features such as custom domains, higher usage limits, and advanced capabilities. This makes it suitable for both individual developers and teams that need more production-ready functionality.</p>
<h2 id="heading-2-tailscale-funnel">2. Tailscale Funnel</h2>
<img src="https://tailscale.com/_next/static/media/funnel-diagram.2f3f0e10.png" alt="Tailscale Funnel img" style="display:block;margin:0 auto" width="2070" height="750" loading="lazy">

<p><a href="https://github.com/tailscale/tailscale">Tailscale Funnel</a> takes a different approach to tunneling than most traditional tools. Built on top of Tailscale's WireGuard-based mesh VPN, it allows developers to securely expose services running inside their private network to the public internet.</p>
<p>The main advantage of Tailscale Funnel is its security-focused design. Instead of relying entirely on a central relay service, Tailscale creates encrypted connections between devices whenever possible. This makes it a popular choice for teams that already use Tailscale for remote access and secure networking.</p>
<p>Tailscale Funnel extends this private network by allowing selected services to be shared publicly. This makes it useful for demos, testing environments, and self-hosted applications that need external access.</p>
<p>The other benefit is its integration with the broader Tailscale ecosystem. Teams can manage devices, access controls, and network permissions from a single platform rather than using separate tools for networking and tunneling.</p>
<p>The drawback is that Tailscale Funnel can be more complex than developer-focused tunneling solutions. Developers looking for a simple "create a tunnel and get a URL" experience may find the networking concepts less straightforward.</p>
<p>For teams that prioritise secure networking and already use Tailscale, Funnel provides a powerful way to expose services without sacrificing security.</p>
<p><strong>Pricing:</strong> Tailscale offers a generous free plan for personal use and small teams. Organisations that need advanced administration, security, and compliance features can upgrade to one of its paid plans.</p>
<h2 id="heading-3-inlets">3. Inlets</h2>
<img src="https://inlets.dev/images/2025-04-one-click-tunnels/background.png" alt="Inlets" style="display:block;margin:0 auto" width="1280" height="720" loading="lazy">

<p><a href="https://inlets.dev/">Inlets</a> is a self-hosted tunneling solution designed for developers and teams that want more control over their infrastructure. Instead of relying on a managed relay service, Inlets allows you to run your own tunnel server in the cloud and securely connect services running on your local machine or private network.</p>
<p>Inlets' biggest strengths are its cloud-native design. It works particularly well with Kubernetes and containerised workloads, making it a popular choice among DevOps engineers and platform teams.</p>
<p>Because the tunnel server runs on infrastructure you control, Inlets gives you greater ownership over security, availability, and network configuration. This can be an important advantage for organisations with compliance requirements or strict security policies.</p>
<p>The other benefit is flexibility. Inlets supports exposing services across cloud environments and private networks without requiring inbound ports to be opened on the origin system.</p>
<p>The drawback is that Inlets requires more setup than fully managed tunneling services. Developers need to provision and maintain a server, which adds operational overhead compared to solutions that work out of the box.</p>
<p>For teams that want a self-hosted, cloud-friendly alternative to Cloudflare Tunnel, Inlets provides a powerful balance between flexibility and control.</p>
<p><strong>Pricing:</strong> Inlets uses a commercial licensing model and also requires you to run your own cloud server. While this introduces some infrastructure costs, it provides complete ownership over your networking environment.</p>
<h2 id="heading-4-frp-fast-reverse-proxy">4. FRP (Fast Reverse Proxy)</h2>
<img src="https://github.com/fatedier/frp/raw/dev/doc/pic/architecture.jpg" alt="Fast Reverse Proxy img" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p><a href="https://github.com/fatedier/frp">FRP (Fast Reverse Proxy)</a> is an open-source reverse proxy application that allows developers to expose services running behind NATs and firewalls to the public internet. Unlike managed tunneling services, FRP is fully self-hosted, giving users complete control over their networking infrastructure.</p>
<p>FRP's biggest strengths are its flexibility. It supports multiple protocols, including TCP, UDP, HTTP, and HTTPS, making it suitable for a wide range of use cases beyond web applications.</p>
<p>Because it's self-hosted, FRP gives organisations full control over their traffic, security policies, and deployment environment. This makes it a popular choice for teams that want to avoid relying on third-party relay services.</p>
<p>The other advantage is its performance and customisation. Developers can configure routing, authentication, and networking behaviour to fit their specific requirements.</p>
<p>The tradeoff is that FRP requires more networking knowledge than most managed tunneling solutions. Initial setup and ongoing maintenance can be more involved, especially for teams without infrastructure experience.</p>
<p>For developers and organisations that want a powerful self-hosted tunneling solution with advanced networking capabilities, FRP remains one of the most flexible alternatives available.</p>
<p><strong>Pricing:</strong> FRP is completely free and open source. Since you host both the client and server yourself, your primary costs are the infrastructure needed to run the tunnel server.</p>
<h2 id="heading-5-tunnelmole">5. Tunnelmole</h2>
<img src="https://tunnelmole.com/img/tunnelmole.png" alt="Tunnelmole img" style="display:block;margin:0 auto" width="512" height="455" loading="lazy">

<p><a href="https://tunnelmole.com/">Tunnelmole</a> is an open-source tunneling tool designed to help developers expose local applications to the internet with minimal setup. It focuses on simplicity, making it a good option for developers who want a lightweight alternative to larger tunneling platforms.</p>
<p>Tunnelmole's biggest advantage is its ease of use. Developers can quickly create public URLs for local applications without dealing with complex networking configurations. This makes it particularly useful for testing, demos, and sharing work in progress.</p>
<p>As an open-source project, Tunnelmole also appeals to developers who prefer transparent tooling. Users can inspect the source code, contribute to the project, or self-host components if needed.</p>
<p>The other benefit is its developer-friendly workflow. Tunnelmole is designed to get developers up and running quickly, allowing them to focus on building applications rather than managing infrastructure.</p>
<p>The tradeoff is that Tunnelmole doesn't offer the same level of advanced networking features, security integrations, or infrastructure control found in some enterprise-focused solutions. Teams with more complex requirements may need a more comprehensive platform.</p>
<p>For developers looking for a simple, open-source way to expose local applications during development, Tunnelmole is a practical and easy-to-use alternative to Cloudflare Tunnel.</p>
<p><strong>Pricing:</strong> Tunnelmole is free and open source. Developers can use the hosted service where available or self-host the project, paying only for the infrastructure they choose to run.</p>
<h2 id="heading-choosing-the-right-cloudflare-tunnel-alternative">Choosing the Right Cloudflare Tunnel Alternative</h2>
<p>Choosing a Cloudflare Tunnel alternative depends on your priorities. Some developers want a simple way to expose local applications, while others need advanced networking features or complete control over their infrastructure.</p>
<p>If you want an easy-to-use tunneling solution with support for multiple protocols, traffic inspection, and custom domains, LocalXpose is one of the strongest options available. It's particularly useful for webhook testing, API development, and sharing local applications during development.</p>
<p>If security and private networking are your main concerns, Tailscale Funnel is worth considering. It combines tunneling with Tailscale's secure mesh networking model, making it a good fit for teams that already use Tailscale.</p>
<p>For teams that want greater infrastructure control, Inlets provides a self-hosted approach that works especially well with Kubernetes and cloud-native environments.</p>
<p>FRP is a strong choice for developers who need a highly flexible self-hosted solution. Its support for multiple protocols and advanced networking configurations makes it suitable for more complex deployments.</p>
<p>If you prefer open-source tools and need a lightweight solution for local development, Tunnelmole offers a simple way to expose applications without additional complexity.</p>
<p>Ultimately, the right choice depends on how you build and deploy applications. Some teams prioritise simplicity, while others focus on security, flexibility, or infrastructure ownership.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Cloudflare Tunnel remains a popular choice for securely exposing applications and services to the internet. Its integration with Cloudflare's broader security and networking platform makes it a strong option for many teams.</p>
<p>But it's no longer the only solution available. Today's tunneling ecosystem offers a variety of alternatives that focus on different priorities, including developer experience, security, self-hosting, and infrastructure control.</p>
<p>LocalXpose stands out as a developer-friendly option with support for multiple protocols, traffic inspection, and an easy setup process. Tailscale Funnel brings a security-first approach through its mesh networking model. Inlets and FRP give teams greater control through self-hosted deployments, while Tunnelmole provides a lightweight open-source option for local development.</p>
<p>The best choice ultimately depends on your requirements. And by understanding the strengths and tradeoffs of each tool, you can choose the solution that best fits your workflow and infrastructure needs.</p>
<p>Thanks for reading.</p>
<p>If you enjoyed this article, you can find more tutorials on self-hosting, Kubernetes, DevOps, and open-source software on my <a href="https://blog.abdultalha.tech/">blog</a>.</p>
<p>You can also connect with me on <a href="https://www.linkedin.com/in/abdul-talha/">LinkedIn</a> to follow my latest articles and projects.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Understanding Proxies and Reverse Proxies: Your Gateway to Secure Networking ]]>
                </title>
                <description>
                    <![CDATA[ As our lives become increasingly digital, the need for secure networking solutions is more important than ever. Whether you’re browsing the web or managing a corporate network, the role of proxies is  ]]>
                </description>
                <link>https://www.freecodecamp.org/news/understanding-proxies-and-reverse-proxies-your-gateway-to-secure-networking/</link>
                <guid isPermaLink="false">69e7e351e4367278149e58cb</guid>
                
                    <category>
                        <![CDATA[ networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ proxy ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Tue, 21 Apr 2026 20:51:29 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/8cf050c7-173f-4298-90e0-8627613c0cab.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As our lives become increasingly digital, the need for secure networking solutions is more important than ever.</p>
<p>Whether you’re browsing the web or managing a corporate network, the role of proxies is critical in maintaining security and efficiency. This article will help you understand what proxies are and how they can enhance your online experiences.</p>
<h3 id="heading-what-well-cover">What We'll Cover:</h3>
<ul>
<li><p><a href="#heading-what-is-a-proxy">What is a Proxy?</a></p>
</li>
<li><p><a href="#heading-benefits-of-forward-proxies">Benefits of Forward Proxies</a></p>
</li>
<li><p><a href="#heading-understanding-reverse-proxies">Understanding Reverse Proxies</a></p>
</li>
<li><p><a href="#heading-other-proxy-types">Other Proxy Types</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-a-proxy"><strong>What is a Proxy?</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/66c6d8f04fa7fe6a6e337edd/6a13adaa-8286-45da-9a6c-8d32d183aff1.png" alt="Proxy Server" style="display:block;margin:0 auto" width="1195" height="344" loading="lazy">

<p>A <a href="https://www.freecodecamp.org/news/a-developers-guide-to-proxy-servers/">proxy server</a> serves as an intermediary between your private network and the public internet.</p>
<p>Think of it as a middleman that manages communications between your devices and the internet. When you send a request to access a website, the proxy server receives it and forwards it to the intended destination, acting on your behalf.</p>
<p>In simpler terms, a proxy server provides a layer of security and privacy by masking your internet activities. It helps ensure that all your online requests are routed appropriately while protecting your network from threats like hackers or malicious sites.</p>
<p>This is especially useful for large networks, where direct internet access can expose vulnerabilities and security risks.</p>
<h2 id="heading-benefits-of-forward-proxies"><strong>Benefits of Forward Proxies</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/66c6d8f04fa7fe6a6e337edd/f29e42e8-1ee8-46e4-8d22-6002357c623d.png" alt="Forward proxy" style="display:block;margin:0 auto" width="1152" height="720" loading="lazy">

<p><a href="https://www.radware.com/cyberpedia/application-delivery/forward-proxy/">Forward proxies</a> offer a multitude of advantages that can enhance network performance and security.</p>
<p>Firstly, they help regulate internet traffic. By controlling the flow of data, you can prevent harmful websites from accessing your network. Also, forward proxies conceal individual IP addresses and present a single interface to the outside world, enhancing your privacy.</p>
<p>Another key benefit of forward proxies is the ability to monitor and log user activity. Organisations can track website visits and the duration of each session, offering insights into user behaviour and accountability.</p>
<p>They also offer an opportunity to bypass restricted content. In highly regulated environments, proxies help in accessing content that might otherwise be restricted.</p>
<p>Last but not least, forward proxies improve speed and efficiency by caching frequently accessed websites. This means these websites load more quickly as they're retrieved from the cache instead of being retrieved from the internet each time.</p>
<h2 id="heading-understanding-reverse-proxies"><strong>Understanding Reverse Proxies</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/66c6d8f04fa7fe6a6e337edd/453a743e-4531-4a72-b907-7b499f7aca28.png" alt="453a743e-4531-4a72-b907-7b499f7aca28" style="display:block;margin:0 auto" width="2881" height="1620" loading="lazy">

<p><a href="https://www.cloudflare.com/en-gb/learning/cdn/glossary/reverse-proxy/">Reverse proxies</a> work in the opposite way by managing the traffic coming into a network rather than the traffic going out. They're particularly useful in protecting servers, enhancing security by creating a single point of entry to the network. This limits direct exposure of servers to potential threats, as external users interact with the reverse proxy rather than the server itself.</p>
<p>A significant benefit of reverse proxies is <a href="https://www.ibm.com/think/topics/load-balancing">load balancing</a>. In complex networks, incoming traffic can overwhelm servers, leading to downtimes. Reverse proxies distribute this traffic evenly, preventing any single server from being overloaded. This ensures smooth operations and maximises server uptime.</p>
<p>Reverse proxies can also protect against <a href="https://www.freecodecamp.org/news/protect-against-ddos-attacks/">Distributed Denial of Service (DDoS)</a> attacks by acting as a buffer. They intercept and block malicious traffic before it reaches the servers, providing an extra layer of security. Reverse proxies also conceal server IP addresses, making it harder for hackers to target specific servers directly.</p>
<h2 id="heading-other-proxy-types"><strong>Other Proxy Types</strong></h2>
<p>There are even more proxy solutions depending on your specific network needs.</p>
<p><a href="https://www.freecodecamp.org/news/us-residential-proxy-why-local-ip-accuracy-matters-for-serp-ads-pricing/">Residential proxies</a> provide anonymous browsing by routing traffic through real IP addresses assigned by Internet Service Providers (ISPs) to actual households. This makes the traffic appear highly legitimate, significantly reducing the chances of detection or blocking by target websites.</p>
<p>They are particularly effective for web scraping, account management, and accessing geo-restricted content because websites treat them as genuine users. But they tend to be more expensive due to the scarcity and operational complexity of maintaining real residential IP pools. Despite the cost, they're often the preferred choice when reliability and stealth are critical.</p>
<p>ISP proxies, also known as static residential proxies, combine the advantages of both residential and datacenter proxies. They're hosted on servers but use IP addresses assigned by ISPs, which gives them the appearance of residential traffic while maintaining high speed and stability.</p>
<p>These proxies are ideal for long-running sessions, automation workflows, and large-scale scraping operations where consistency is important. Businesses often rely on ISP proxies when they need both performance and trustworthiness without frequent IP rotation. They strike a balance between cost, speed, and legitimacy, making them a versatile option.</p>
<p><a href="https://www.scrapingbee.com/blog/isp-proxy/">Datacenter proxies</a> are generated from cloud servers or data centers rather than real residential networks. They're known for their high speed, low latency, and cost-effectiveness, making them suitable for tasks that require rapid data extraction or bulk operations.</p>
<p>But because they originate from identifiable server ranges, websites can more easily detect and block them compared to residential or ISP proxies. They're best used for non-sensitive scraping tasks, testing environments, or scenarios where scale and speed are prioritized over stealth. Many teams use them as a first layer before switching to more sophisticated proxy types if needed.</p>
<p><a href="https://fleetproxy.io/blog/how-to-buy-mobile-proxies-for-web-testing">Mobile proxies</a> route traffic through IP addresses assigned to mobile devices via cellular networks such as 4G or 5G. These IPs are highly trusted by websites because mobile carriers use techniques like carrier-grade NAT, where many users share the same IP, making blocking less effective.</p>
<p>As a result, mobile proxies offer the highest level of anonymity and are extremely effective at bypassing strict anti-bot and anti-scraping mechanisms. They're commonly used for social media automation, ad verification, and accessing mobile-specific content. While they're typically the most expensive option, their success rate in difficult environments often justifies the investment.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Proxies  –  be it forward or reverse  –&nbsp;represent a crucial piece of today’s network security and efficiency puzzle. Forward proxies protect client devices by regulating outgoing internet traffic and masking individual identities, while reverse proxies safeguard servers by controlling incoming traffic and offering load balancing.</p>
<p>By leveraging these proxy solutions, you can ensure enhanced network security and improved functionality. Whether you’re a business looking to protect server data or a user interested in anonymous browsing, choosing the right proxy solution can make a significant difference in maintaining a secure and efficient digital presence.</p>
<p><em>Join my</em> <a href="https://applyaito.substack.com/"><em><strong>Applied AI newsletter</strong></em></a> <em>to learn how to build and ship real AI systems. Practical projects, production-ready code, and direct Q&amp;A. You can also</em> <a href="https://www.linkedin.com/in/manishmshiva/"><em><strong>connect with me on</strong></em> <em><strong>LinkedIn</strong></em></a><em><strong>.</strong></em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Computer Networking Fundamentals ]]>
                </title>
                <description>
                    <![CDATA[ How does the Internet really work? For many technical jobs it is important to understand computer networking. We just posted a massive 12-hour course that will give you a deep dive into computer networking. Here are the sections covered in this compr... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/computer-networking-fundamentals/</link>
                <guid isPermaLink="false">6995e32376926e7d4ed2c700</guid>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 18 Feb 2026 16:04:51 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1771430669203/458df2d4-6920-4f6f-a30a-aecfa4635309.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>How does the Internet really work?</p>
<p>For many technical jobs it is important to understand computer networking. We just posted a massive 12-hour course that will give you a deep dive into computer networking.</p>
<p>Here are the sections covered in this comprehensive course:</p>
<p><strong>Course Overview &amp; Methodology</strong></p>
<ul>
<li><p>Fundamental Concepts and Networking Stack</p>
</li>
<li><p>Orientation: Curriculum and Prerequisite (DSA)</p>
</li>
<li><p>Introduction to the Instructor: Shrathir Sharma</p>
</li>
<li><p>Course Access (YouTube/Udemy) and Target Audience</p>
</li>
<li><p>Teaching Methodology: Raw Pen &amp; Paper Style</p>
</li>
<li><p>Core Modules: IPv4, Error Control, and Flow Control</p>
</li>
<li><p>Core Modules: Transport, Media Access, and Routing</p>
</li>
<li><p>Bonus Module: Cybersecurity</p>
</li>
</ul>
<p><strong>Networking Basics</strong></p>
<ul>
<li><p>Defining a Computer Network</p>
</li>
<li><p>Why Networks Interact: Resource Sharing</p>
</li>
<li><p>5 Components of Data Communication</p>
</li>
<li><p>4 Metrics for Network Effectiveness</p>
</li>
<li><p>Transmission Modes: Simplex, Half-Duplex, Full-Duplex</p>
</li>
<li><p>Types of Connections: Point-to-Point vs. Multi-Point</p>
</li>
</ul>
<p><strong>Topology &amp; Architecture</strong></p>
<ul>
<li><p>Introduction to Topology Layouts</p>
</li>
<li><p>Mesh Topology and Link Calculations</p>
</li>
<li><p>Advantages and Disadvantages of Topologies</p>
</li>
<li><p>Star, Bus, and Ring Topology Details</p>
</li>
<li><p>The OSI Model Framework</p>
</li>
<li><p>Layered Architecture and Peer-to-Peer Protocols</p>
</li>
</ul>
<p><strong>Binary &amp; IP Addressing Foundations</strong></p>
<ul>
<li><p>Review of Lecture Zero</p>
</li>
<li><p>Binary Number Representation &amp; Conversion</p>
</li>
<li><p>Binary Weights and Octet Conversions</p>
</li>
<li><p>Introduction to IPv4 Logical Addressing</p>
</li>
<li><p>Network ID vs. Host ID and IANA Authority</p>
</li>
</ul>
<p><strong>Classful vs. Classless Addressing</strong></p>
<ul>
<li><p>Telephone Network Analogy for IP Classes</p>
</li>
<li><p>Class A, B, and C Breakdown</p>
</li>
<li><p>Classful Wastage and the Need for Classless (CIDR)</p>
</li>
<li><p>Implementation: Fixing Bits for Classes A-E</p>
</li>
<li><p>IP Address Space Distribution</p>
</li>
<li><p>Hexadecimal and Decimal IP Representations</p>
</li>
</ul>
<p><strong>IPv4 Addressing Deep Dive</strong></p>
<ul>
<li><p>Class A Details: Reserved Addresses &amp; 127.0.0.1 Loopback</p>
</li>
<li><p>Calculating Valid Hosts and Reserved All-Zeros/All-Ones</p>
</li>
<li><p>Loopback Testing &amp; Troubleshooting Connectivity</p>
</li>
<li><p>Class B Details: Network Ranges &amp; Host Capacity</p>
</li>
<li><p>Class C Details: Network/Host Ratios</p>
</li>
<li><p>Class D (Multicasting) and Class E (Experimental)</p>
</li>
<li><p>IP Conversion Practice: Hexadecimal to Decimal</p>
</li>
<li><p>Common Pitfalls: "Addresses" vs. "Valid Hosts"</p>
</li>
</ul>
<p><strong>Subnetting &amp; VLSM</strong></p>
<ul>
<li><p>Introduction to Subnetting: Why We Divide Networks</p>
</li>
<li><p>Disadvantages of Subnetting: Wastage and Cost</p>
</li>
<li><p>How to Subnet: Borrowing Bits from Host ID</p>
</li>
<li><p>Subnet Identification: Calculating Subnet IDs and DBAs</p>
</li>
<li><p>Working with Weights: Identifying Specific Subnets</p>
</li>
<li><p>Subnet Masks vs. Network Masks</p>
</li>
<li><p>Designing a Subnet Mask for Specific Requirements</p>
</li>
<li><p>Variable Length Subnet Masking (VLSM) Strategy</p>
</li>
<li><p>Determining Subnet IDs using Bitwise AND Operations</p>
</li>
<li><p>Routing Tables: Matching Destination IPs to Interfaces</p>
</li>
<li><p>CIDR: Classless Inter-Domain Routing &amp; Slash Notation</p>
</li>
<li><p>Rules for Valid CIDR Blocks</p>
</li>
<li><p>Supernetting: Merging Multiple Blocks</p>
</li>
</ul>
<p><strong>Error Control &amp; Detection</strong></p>
<ul>
<li><p>Introduction to Error Control: Noise vs. Security</p>
</li>
<li><p>Single Bit Error vs. Burst Errors</p>
</li>
<li><p>Redundant Bits and Block Coding Logic</p>
</li>
<li><p>Hamming Distance: Calculating Difference Between Strings</p>
</li>
<li><p>Minimum Hamming Distance for Detection and Correction</p>
</li>
<li><p>Simple Parity: Even vs. Odd Parity Methods</p>
</li>
<li><p>2D Parity: Detecting and Correcting Single Bit Errors</p>
</li>
<li><p>Limitations of 2D Parity for Multi-Bit Errors</p>
</li>
<li><p>Cyclic Redundancy Check (CRC): Divisor &amp; Remainder Logic</p>
</li>
<li><p>Checksum: One's Complement Summation Method</p>
</li>
</ul>
<p><strong>Flow Control &amp; Layered Architecture</strong></p>
<ul>
<li><p>Network Delays: Transmission vs. Propagation</p>
</li>
<li><p>Queuing and Processing Delays</p>
</li>
<li><p>Data Encapsulation: Headers and Trailers</p>
</li>
<li><p>The Need for Flow Control: Avoiding Receiver Overwhelm</p>
</li>
<li><p>Stop and Wait Protocol: Core Mechanism</p>
</li>
<li><p>Using Timers and Sequence Numbers</p>
</li>
<li><p>Calculating Efficiency and Round Trip Time (RTT)</p>
</li>
<li><p>Throughput: Effective Bandwidth Relationship</p>
</li>
<li><p>Sliding Window Concept: Improving Efficiency</p>
</li>
<li><p>Go-Back-N (GBN) Protocol: Sender/Receiver Windows</p>
</li>
<li><p>Selective Repeat (SR) Protocol: Out-of-Order Handling</p>
</li>
<li><p>Cumulative vs. Independent Acknowledgments</p>
</li>
</ul>
<p><strong>Network Layer: IP Header &amp; Routing</strong></p>
<ul>
<li><p>IPv4 Header Format Overview</p>
</li>
<li><p>Type of Services (TOS): Priority and DTRC Bits</p>
</li>
<li><p>Time to Live (TTL): Preventing Infinite Loops</p>
</li>
<li><p>Protocol Field and Header Checksum</p>
</li>
<li><p>IP Options: Strict vs. Loose Source Routing</p>
</li>
<li><p>TCP Header Structure: Ports, Sequence, and Ack</p>
</li>
<li><p>Wrap Around Time and Segment Lifetime</p>
</li>
<li><p>Advertisement Window (Flow Control)</p>
</li>
<li><p>TCP Control Flags: URG, ACK, PSH, RST, SYN, FIN</p>
</li>
<li><p>SYN Flooding Attack (DDoS)</p>
</li>
<li><p>Congestion Control Policy: Slow Start &amp; Avoidance</p>
</li>
<li><p>TCP Timers: Time-Wait, Keep-Alive, Persistent</p>
</li>
<li><p>UDP Header and Best-Effort Delivery</p>
</li>
<li><p>Comparison: TCP vs. UDP</p>
</li>
</ul>
<p><strong>Media Access &amp; Application Support</strong></p>
<ul>
<li><p>Multiple Access: Random vs. Controlled Access</p>
</li>
<li><p>Pure Aloha vs. Slotted Aloha Throughput</p>
</li>
<li><p>CSMA (Carrier Sense): Persistent Methods</p>
</li>
<li><p>Polling, Reservation, and Token Passing</p>
</li>
<li><p>Routing: Flooding vs. Dynamic Routing</p>
</li>
<li><p>Distance Vector (Bellman-Ford) vs. Link State (Dijkstra)</p>
</li>
<li><p>Circuit Switching vs. Packet Switching</p>
</li>
<li><p>Email Protocols: SMTP, POP3, IMAP4</p>
</li>
<li><p>Domain Name System (DNS) Hierarchy &amp; Queries</p>
</li>
<li><p>FTP (File Transfer) and HTTP (Web Services)</p>
</li>
<li><p>Support Protocols: ARP and ICMP Error Reporting</p>
</li>
<li><p>Final Summary: OSI Model Layers 1-7</p>
</li>
</ul>
<p>Watch the full course on <a target="_blank" href="https://youtu.be/fQbBPa0ADvs">the freeCodeCamp.org YouTube channel</a> (12-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/fQbBPa0ADvs" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How TCP Turns Round Trip Time and Jitter into Packet Loss ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever noticed that your network connection sometimes feels fast and then suddenly slow, even when nothing obvious has changed? A request that takes 20 ms at one moment can take 80 ms the next, and sometimes it does not return at all. Terms li... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-tcp-turns-round-trip-time-and-jitter-into-packet-loss/</link>
                <guid isPermaLink="false">69837b8b9eb9655b2349db75</guid>
                
                    <category>
                        <![CDATA[ networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Packet Loss ]]>
                    </category>
                
                    <category>
                        <![CDATA[ rtt ]]>
                    </category>
                
                    <category>
                        <![CDATA[ jitter ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Syeda Maham Fahim ]]>
                </dc:creator>
                <pubDate>Wed, 04 Feb 2026 17:02:03 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770224386950/ceeafb62-ae8c-4c70-8239-91ba835b85b7.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever noticed that your network connection sometimes feels fast and then suddenly slow, even when nothing obvious has changed? A request that takes 20 ms at one moment can take 80 ms the next, and sometimes it does not return at all. Terms like RTT, jitter, and packet loss are often used to explain this behavior, but the real connection between them is easy to miss.</p>
<p>In this article, we’ll look at RTT, jitter, and packet loss as parts of a single timing system rather than separate metrics. You’ll start by understanding RTT and why it changes over time. Then you’ll learn how jitter emerges as an extra delay relative to a baseline. Finally, you’ll see how TCP uses this timing information to decide when delay turns into packet loss, with a focus on real protocol behaviour such as TLS and post-quantum TLS handshakes.</p>
<p>The goal is simple: to understand how timing turns into decisions.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-rtt-round-trip-time">RTT (Round Trip Time)</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-baseline-rtt">Baseline RTT</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-baseline-rtt-matters">Why Baseline RTT Matters</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-jitter">What is Jitter?</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-jitter-actually-means">What Jitter Actually Means</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-where-jitter-comes-from">Where Jitter Comes From</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-jitter-tells-us">What Jitter Tells Us</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-tcp-learns-rtt-and-jitter">How TCP Learns RTT and Jitter</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-tcp-does-not-know-rtt-in-advance">TCP Does Not Know RTT in Advance</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-srtt-smoothed-rtt">SRTT (Smoothed RTT)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-rttvar-rtt-variance">RTTVAR (RTT Variance)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-tcp-needs-both">Why TCP Needs Both</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-tcp-decides-packet-loss">How TCP Decides Packet Loss</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-tcp-never-sees-a-packet-being-dropped">TCP Never Sees a Packet Being Dropped</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-retransmission-timeout-rto">Retransmission Timeout (RTO)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-delay-vs-packet-loss">Delay vs Packet Loss</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-jitter-turns-into-packet-loss">How Jitter Turns Into Packet Loss</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-rtt-round-trip-time">RTT (Round Trip Time)</h2>
<p>Before talking about delay, jitter, or packet loss, we need to clearly understand what RTT is. If RTT is not clear, everything that comes after it becomes confusing.</p>
<p>RTT stands for <strong>Round Trip Time</strong>. It is the total time taken for a packet to travel from a client to a server and for the response to return to the client.</p>
<p><a target="_blank" href="speedvitals.com"><img src="https://cdn-images-1.medium.com/max/1600/1*tKeOZNVYvkDuXMl4WytN5Q.jpeg" alt="RTT [Image Source: speedvitals.com ]" width="600" height="400" loading="lazy"></a></p>
<p>Assuming you send a packet and receive the reply after 50 milliseconds, then the RTT is 50 ms. That is the basic definition.</p>
<p>But here is the important part: <strong>RTT is not a fixed number.</strong> It changes all the time. Even when you communicate with the same server, RTT can change from one packet to the next. This happens because the network is always changing, and this can be because of any of these reasons:</p>
<ul>
<li><p>Packets waiting in queues</p>
</li>
<li><p>Temporary congestion</p>
</li>
<li><p>Scheduling inside routers</p>
</li>
<li><p>Background traffic on the same path</p>
</li>
</ul>
<p>Let’s assume you connect to Google, and you send a packet now. In practice, RTT can be measured using simple tools. One common way is the <code>ping</code> command, which sends a packet and measures how long it takes for the reply to return.</p>
<pre><code class="lang-python">ping -n <span class="hljs-number">1</span> google.com
</code></pre>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*_cGYjq_VgETjsV6rl6XLZA.png" alt="Ping to google.com showing round-trip time output." width="600" height="400" loading="lazy"></p>
<p>And here, you get the reply after 50 ms.</p>
<pre><code class="lang-python">RTT = <span class="hljs-number">50</span> ms
</code></pre>
<p>That value is real, but it is incomplete. A single RTT measurement does not tell us whether the network path itself takes 50 ms, or whether the path is faster and the packet experienced a small temporary delay along the way.</p>
<p>For example, the actual path delay might be 49 ms, with an additional 1 ms spent waiting in a queue. From a single RTT value, there is no way to separate these effects. RTT only makes sense after multiple measurements.</p>
<p>So, let’s measure multiple RTT values.</p>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*ecgJnU89HtE9FVzczJue4g.png" alt="Ping to google.com showing multiply round-trip time output." width="600" height="400" loading="lazy"></p>
<p>Now you can see a pattern. From the measurements:</p>
<pre><code class="lang-python">min RTT ≈ <span class="hljs-number">18</span> ms
max RTT ≈ <span class="hljs-number">19</span> ms
average RTT ≈ <span class="hljs-number">18</span> ms
</code></pre>
<p>That is why RTT is not something you magically know from one packet. It is something you observe over time.</p>
<p>But now, at this point, an important question comes up: <strong>Which of these RTT values represents the real network path?</strong></p>
<p>When RTT is measured repeatedly, the values are not consistent. Some RTT measurements are small, some are larger, and some suddenly jump due to temporary network conditions.</p>
<p>You may see something like this: <code>small, small, small, small, BIG</code>. That is why we need a reference point, which we can call the stable point. Without it, every RTT value looks equally confusing, and we cannot tell whether a packet was slow because the path itself is slow or because something temporary happened.</p>
<h3 id="heading-baseline-rtt">Baseline RTT</h3>
<p>That stable point is the baseline RTT. Baseline RTT means the <strong>minimum RTT observed over time</strong>. This represents the RTT without temporary effects.</p>
<p>For example, in the above example, our repeated measurements show minimum RTT ≈ 18 ms. 18 ms becomes our baseline RTT. You can think of baseline RTT as the fastest possible RTT for a given path, representing the calm state of the network where packets do not wait in queues, there is no congestion, and no retransmissions occur.</p>
<p>In other words, baseline RTT reflects what the network is capable of when nothing unusual is happening. The best happy case that usually excludes temporary effects.</p>
<h3 id="heading-why-baseline-rtt-matters"><strong>Why Baseline RTT Matters</strong></h3>
<p>Once we have a baseline RTT, individual RTT measurements stop feeling random. We can see when an RTT is close to the baseline, when it is higher than expected, and when extra delay has been introduced by temporary network conditions.</p>
<p>Without a baseline RTT, each RTT value stands alone, and comparison becomes guesswork. With a baseline in place, RTT values gain meaning, variation becomes visible, and we are finally able to reason about what causes RTT to increase, which naturally leads to jitter.</p>
<p>This is the point where we are finally ready to talk about <strong>what causes RTT to increase</strong>, which leads naturally to jitter.</p>
<h2 id="heading-what-is-jitter">What is Jitter?</h2>
<p>Now comes Jitter. Once we have a baseline RTT, something important becomes clear. Most RTT values are not equal to the baseline. They are usually higher.</p>
<p>So the next natural question is: <strong>If baseline RTT shows the calm network, what is causing the RTT to increase in the other measurements?</strong></p>
<p>That extra part is what we call jitter.</p>
<h3 id="heading-what-jitter-actually-means">What Jitter Actually Means</h3>
<p>Jitter is the extra delay added on top of the baseline RTT. In simple words, baseline RTT shows what the network can do when nothing is wrong, while jitter describes what happens when the network becomes busy, and packets experience extra delay.</p>
<p>So every observed RTT can be thought of like this: <code>Observed RTT = Baseline RTT + Extra Delay</code></p>
<p><strong><em>Example</em></strong></p>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*T6bC3VvXULV5CIVRixg-uA.png" alt="Observed RTT and Jitter." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Baseline RTT = 18 ms. That extra delay is jitter.</p>
<p>There are two important points to remember. First, jitter is always positive because a packet can be delayed but can never arrive faster than the baseline RTT. Second, baseline RTT acts as the reference point, which means jitter only exists relative to that baseline. Without a baseline, jitter has no meaning.</p>
<h3 id="heading-where-jitter-comes-from">Where Jitter Comes From</h3>
<p>Jitter appears when packets do not move immediately through the network.</p>
<p>This usually happens because of:</p>
<ul>
<li><p>Packets waiting in queues</p>
</li>
<li><p>Routers delaying packets before forwarding</p>
</li>
<li><p>Temporary congestion on links</p>
</li>
<li><p>Retransmissions after drops</p>
</li>
</ul>
<p>These effects are not constant. They come and go. Because of that, jitter is irregular and bursty. Sometimes it is very small, and at other times it can suddenly become large.</p>
<h3 id="heading-what-jitter-tells-us">What Jitter Tells Us</h3>
<p>At this stage, jitter is still just an observation. It tells us how unstable the network timing is and how often packets experience extra delay. We are not making decisions yet. We are only describing what the network is doing.</p>
<h2 id="heading-how-tcp-learns-rtt-and-jitter">How TCP Learns RTT and Jitter</h2>
<p>We have seen that:</p>
<ul>
<li><p>RTT changes over time</p>
</li>
<li><p>Baseline RTT gives us a reference</p>
</li>
<li><p>Jitter explains extra delay</p>
</li>
</ul>
<p>So, up to this point, we have only been observing the network. But now a new question appears: If RTT keeps changing, and if delay and jitter exist, <strong>who is actually watching all this?</strong> More importantly, <strong>who decides when waiting is normal and when waiting becomes a problem?</strong></p>
<p>This is the point where <strong>TCP</strong> enters the picture. TCP is the component that observes these timing changes and uses them to decide what to do next.</p>
<h3 id="heading-tcp-does-not-know-rtt-in-advance">TCP Does Not Know RTT in Advance</h3>
<p>TCP does not start with any knowledge of how long the path is, how stable the network will be, or how much delay to expect. It learns all of this dynamically while the connection is running.</p>
<p>TCP learns everything <strong>while the connection is running</strong>, only by looking at time. Every time TCP sends data and receives an acknowledgement, it gets one RTT sample. Over time, these samples are used to build expectations.</p>
<p>To make sense of these timing samples, TCP maintains two internal values that summarize what it has learned so far.</p>
<h3 id="heading-srtt-smoothed-rtt">SRTT (Smoothed RTT)</h3>
<p>SRTT is the RTT that TCP expects most of the time. It is not the minimum RTT, and it is not a simple average. It is a smoothed value that represents the normal RTT that the TCP has learned from recent history. This means recent RTT measurements matter more, while older RTT measurements gradually matter less.</p>
<p>Because of this, SRTT does not jump because of a single delayed packet. Instead, it adapts gradually as network conditions change.</p>
<p>For example, suppose TCP observes these RTT samples (in ms): 48, 50, 49, 51, 50.</p>
<p>Then TCP smooths these values into a stable expectation, such as: SRTT ≈ 50 ms.</p>
<p>You can think of SRTT as: The RTT that TCP believes is reasonable for this connection, based mostly on recent history. It is a memory-weighted average, biased toward recent RTT values.</p>
<h3 id="heading-rttvar-rtt-variance">RTTVAR (RTT Variance)</h3>
<p>RTTVAR tells TCP <strong>how much RTT is changing</strong>. Now compare two situations.</p>
<p><strong>Stable RTT</strong></p>
<p>RTT samples: <code>49, 50, 51, 50</code></p>
<p>Because these values are close to each other, the variation is small, RTTVAR remains low, and TCP feels confident about its timing estimates.</p>
<p><strong>Unstable RTT</strong></p>
<p>RTT samples: <code>50, 52, 90, 48</code></p>
<p>Here, the sudden jump increases variation, causes RTTVAR to rise, and makes TCP less confident about its timing.</p>
<h3 id="heading-why-tcp-needs-both">Why TCP Needs Both</h3>
<p>SRTT alone is not enough for TCP to make reliable timing decisions. If TCP only knew that the RTT is around 50 ms, it would still have no way to tell whether delays are stable or whether sudden spikes are common.</p>
<p>RTTVAR fills this gap by capturing how much RTT changes over time. While SRTT tells TCP what RTT to expect under normal conditions, RTTVAR tells TCP how confident it should be in that expectation.</p>
<p>At this stage, TCP is still <strong>learning</strong>, not judging. It is building a timing model of the network.</p>
<p>So far, the network produces RTT variation, baseline RTT provides a calm reference, jitter explains extra delay, and TCP observes all of this using SRTT and RTTVAR.</p>
<p>TCP now has expectations. Only after this point does TCP start making decisions. And one of those decisions is packet loss.</p>
<h2 id="heading-how-tcp-decides-packet-loss">How TCP Decides Packet Loss</h2>
<p>Now that TCP has learned what RTT usually looks like and how much it varies, it has to answer one important question: <strong>How long should I wait before assuming a packet is gone?</strong></p>
<p>This is where packet loss comes in.</p>
<h3 id="heading-tcp-never-sees-a-packet-being-dropped">TCP Never Sees a Packet Being Dropped</h3>
<p>TCP does not see routers, queues, or links, and it does not know where packets go. TCP only sees time. It sends data and then waits.</p>
<p>If the acknowledgment arrives in time, everything is fine. If it does not, TCP must decide what to do next.</p>
<h3 id="heading-retransmission-timeout-rto">Retransmission Timeout (RTO)</h3>
<p>To make this decision, TCP uses the Retransmission Timeout, or RTO. RTO is not random. It is computed from what TCP has already learned about network timing.</p>
<p>Conceptually, RTO is calculated as:</p>
<pre><code class="lang-markdown">RTO=SRTT+max(𝐺,4×RTTVAR)
</code></pre>
<p>Here, SRTT sets the expected delay, while RTTVAR adds extra margin to account for jitter. As a result, RTO represents how long TCP is willing to wait, based on how uncertain the network timing is.</p>
<p>Suppose TCP has learned that the SRTT is 50 ms and the RTTVAR is 5 ms. In that case, the RTO becomes 70 ms.</p>
<p>RTO = 50 + 4 × 5<br>RTO = 70 ms</p>
<p>Now TCP behavior is simple:</p>
<ul>
<li><p>ACK arrives at <strong>60 ms</strong> → delay</p>
</li>
<li><p>ACK arrives at <strong>75 ms</strong> → packet loss</p>
</li>
</ul>
<p>The network is the same, and the packet is the same. Only the arrival time changes, and that alone leads to a different decision.</p>
<h3 id="heading-delay-vs-packet-loss">Delay vs Packet Loss</h3>
<p>TCP logic is simple. If a packet arrives before the RTO expires, it is treated as delay. If it does not arrive before the RTO, TCP declares it lost.</p>
<p>This leads to an important rule: <strong>packet loss is a timing decision, not a certainty</strong>. The packet may still arrive later, but once the RTO expires, TCP has already acted.</p>
<h3 id="heading-how-jitter-turns-into-packet-loss">How Jitter Turns Into Packet Loss</h3>
<p>This behaviour connects directly to jitter. As long as jitter stays within the RTO window, packets are delayed but not considered lost. When jitter becomes large enough that delays cross the RTO boundary, TCP interprets delay as packet loss.</p>
<p>So packet loss does not always mean a packet disappeared. Often, it means the network timing has become too unpredictable.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>At this point, everything connects: RTT, jitter, and packet loss are not separate network metrics. They describe different parts of the same timing process.</p>
<ul>
<li><p>RTT shows how long communication usually takes.</p>
</li>
<li><p>Baseline RTT gives a stable reference.</p>
</li>
<li><p>Jitter explains why delays change.</p>
</li>
<li><p>Packet loss appears when that variation exceeds what the protocol can tolerate.</p>
</li>
</ul>
<p>Once this flow is clear, network behavior stops feeling random. It becomes a matter of timing, uncertainty, and decisions.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A Developer’s Guide to Proxy Servers ]]>
                </title>
                <description>
                    <![CDATA[ Every time you open a website, your device talks directly to another server on the internet.  Your IP address, location, and basic network details are visible to that server.  In many cases, this is fine. But there are situations where you may want m... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-developers-guide-to-proxy-servers/</link>
                <guid isPermaLink="false">695db23365ab0e59d902fa64</guid>
                
                    <category>
                        <![CDATA[ proxy ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ server ]]>
                    </category>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ networking ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Wed, 07 Jan 2026 01:09:07 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1767748085260/ef495b53-f484-4f55-af29-57432aaf1dba.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Every time you open a website, your device talks directly to another server on the internet. </p>
<p>Your IP address, location, and basic network details are visible to that server. </p>
<p>In many cases, this is fine. But there are situations where you may want more control over how your requests travel across the internet. This is where proxies come in.</p>
<p>A <a target="_blank" href="https://www.geeksforgeeks.org/computer-networks/what-is-proxy-server/">proxy</a> acts as an intermediary between you and the internet. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767634042506/560a0ace-c42e-4810-b5d1-fbb9a1a6a246.png" alt="How Proxy Works" class="image--center mx-auto" width="1000" height="600" loading="lazy"></p>
<p>Instead of your device connecting directly to a website, it sends the request to a proxy server. The proxy then forwards the request on your behalf and sends the response back to you. </p>
<p>From the website’s point of view, it’s the proxy that is making the request, not you.</p>
<p>Proxies are used for privacy, security, performance, testing, automation, and access control. They are common in companies, data centers, scraping systems, and even home networks. </p>
<p>To understand why proxies matter, it helps to first understand how internet requests normally work.</p>
<h2 id="heading-what-well-cover"><strong>What We’ll Cover</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-internet-requests-work-without-a-proxy">How internet requests work without a proxy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-types-of-proxies">Types of proxies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-proxies-vs-vpns">Proxies vs VPNs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-using-a-proxy-in-python">Using a proxy in Python</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-proxy-use-cases">Proxy Use Cases</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-proxies-affect-performance-and-reliability">How proxies affect performance and reliability</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-proxies-are-detected-and-blocked">How proxies are detected and blocked</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-security-considerations-when-using-proxies">Security considerations when using proxies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-how-internet-requests-work-without-a-proxy"><strong>How Internet Requests Work Without a Proxy</strong></h2>
<p>When you type a website address into your browser, your computer resolves the domain name to an IP address using DNS. It then opens a connection directly to that server. </p>
<p>Your IP address is included as part of the network connection so the server knows where to send the response.</p>
<p>The server can log your IP address, infer your location, detect your network provider, and apply rules based on that information. Some websites restrict access by country. </p>
<p>Others rate-limit or block traffic from specific IP ranges. In automated systems, repeated requests from the same IP are often flagged as suspicious.</p>
<p>Without a proxy, all of this traffic is directly tied to your device or server. There is no separation layer.</p>
<h2 id="heading-types-of-proxies"><strong>Types of Proxies</strong></h2>
<p>Proxies come in several forms, each designed for different scenarios.</p>
<p><a target="_blank" href="https://www.zscaler.com/resources/security-terms-glossary/what-is-forward-proxy">Forward proxies</a> are the most common. These are used by clients to access external resources. Corporate networks often use forward proxies to control employee internet access.</p>
<p><a target="_blank" href="https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/">Reverse proxies</a> work in the opposite direction. They sit in front of servers rather than clients. Websites use reverse proxies to load balance traffic, terminate TLS, and protect backend systems.</p>
<p>Transparent proxies operate without explicit client configuration. They intercept traffic at the network level. These are often used by ISPs or enterprise networks.</p>
<p>Residential, datacenter, and mobile proxies differ based on where their IP addresses come from. Residential and mobile proxies appear like real user devices, while datacenter proxies come from cloud providers.</p>
<h2 id="heading-proxies-vs-vpns"><strong>Proxies vs VPNs</strong></h2>
<p>Proxies and VPNs are often confused, but they solve different problems. A proxy usually works at the application level. You configure a browser, script, or tool to use a proxy, and only that traffic goes through it.</p>
<p>A VPN works at the operating system or network level. Once connected, all traffic from your device is routed through the <a target="_blank" href="https://www.paloaltonetworks.com/cyberpedia/what-is-a-vpn-tunnel">VPN tunnel</a> by default. This includes browsers, apps, and background services.</p>
<p>Another difference is encryption. Most VPNs encrypt traffic between your device and the VPN server. Many proxies don’t, unless you’re using HTTPS or a secure proxy protocol.</p>
<p>People sometimes compare proxies to a <a target="_blank" href="https://nordvpn.com/">free VPN</a>, especially when the goal is hiding an IP address. While both can change your apparent location, a proxy is usually more lightweight and task-specific. A VPN is better when you want system-wide privacy, but it comes with more overhead and less fine-grained control.</p>
<p>For developers and automation systems, proxies are often preferred because they are easier to rotate, cheaper at scale, and simpler to integrate into code.</p>
<h2 id="heading-using-a-proxy-in-python"><strong>Using a Proxy in Python</strong></h2>
<p>Using a proxy in Python is straightforward, especially with popular libraries like <code>requests</code>. Below is a simple example that sends an HTTP request through a proxy.</p>
<p>To get a proxy URL, you can either build your own proxy using open-source solutions like <a target="_blank" href="https://www.manageengine.com/products/firewall/tech-topics/what-is-squid-proxy.html">SquidProxy</a> or buy a third-party service that charges per GB of traffic. Here is a list of <a target="_blank" href="https://www.geeksforgeeks.org/websites-apps/best-residential-proxy-providers/">popular proxy providers</a>. </p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests  <span class="hljs-comment"># Import the requests library to make HTTP requests</span>

<span class="hljs-comment"># Proxy URL with authentication details</span>
<span class="hljs-comment"># Format: protocol://username:password@host:port</span>
proxy_url = <span class="hljs-string">"http://username:password@proxy_host:proxy_port"</span>


<span class="hljs-comment"># Define proxy settings for both HTTP and HTTPS traffic</span>
<span class="hljs-comment"># Requests will route all outgoing traffic through this proxy</span>
proxies = {
   <span class="hljs-string">"http"</span>: proxy_url,
   <span class="hljs-string">"https"</span>: proxy_url
}

<span class="hljs-comment"># Make a GET request to httpbin.org, which returns the IP address</span>
<span class="hljs-comment"># This helps verify whether the request is going through the proxy</span>
response = requests.get(
   <span class="hljs-string">"https://httpbin.org/ip"</span>,  <span class="hljs-comment"># Test endpoint that echoes the client IP</span>
   proxies=proxies,          <span class="hljs-comment"># Apply the proxy configuration</span>
   timeout=<span class="hljs-number">10</span>                <span class="hljs-comment"># Fail the request if it takes more than 10 seconds</span>
)

<span class="hljs-comment"># Print the response body</span>
<span class="hljs-comment"># If the proxy is working, the IP shown here will be the proxy's IP, not yours</span>
print(response.text)
</code></pre>
<p>In this example, the requests library sends the outbound request to the proxy instead of directly to the website. The website sees the proxy’s IP address. The response shows which IP was used, making it easy to verify that the proxy is working.</p>
<p>This same pattern applies to APIs, scrapers, and internal tools. More advanced setups rotate proxies per request or per session.</p>
<h2 id="heading-proxy-use-cases"><strong>Proxy Use Cases</strong></h2>
<p>One of the most common reasons to use a proxy is IP masking. By routing traffic through a proxy, your real IP address is hidden from the destination server. This is useful for privacy, security testing, and bypassing IP-based restrictions.</p>
<p>Proxies are also used for geographic routing. If a service behaves differently in different countries, a proxy located in a specific region lets you see what users there experience.</p>
<p>In automation and scraping systems, proxies are essential. Sending thousands of requests from a single IP is a fast way to get blocked. Rotating proxies distribute traffic across many IPs, reducing detection.</p>
<p>Companies use proxies to monitor, filter, and log outbound traffic. This helps with compliance, security, and performance optimisation.</p>
<h2 id="heading-how-proxies-affect-performance-and-reliability"><strong>How Proxies Affect Performance and Reliability</strong></h2>
<p>Adding a proxy introduces an extra network hop, which can increase latency. A well-located, high-quality proxy can still be fast, but performance depends heavily on proxy capacity and distance.</p>
<p>Proxies can also improve performance in some cases. Caching proxies store responses and serve them locally for repeated requests. This reduces load on upstream servers and speeds up access.</p>
<p>Reliability depends on proxy health. If a proxy goes down, all traffic routed through it fails. This is why production systems often use proxy pools and health checks to automatically switch between proxies.</p>
<h2 id="heading-how-proxies-are-detected-and-blocked"><strong>How Proxies Are Detected and Blocked</strong></h2>
<p>Websites often try to detect proxy usage. They analyse IP reputation, request patterns, headers, and behavioural signals. Datacenter proxies are easier to detect because their IP ranges are well-known.</p>
<p>Some proxies leak information through headers that reveal the original client IP. Poorly configured proxies are especially easy to spot.</p>
<p>To reduce detection, systems rotate IPs, randomise headers, simulate real browser behaviour, and use residential or mobile proxies. Detection and evasion is an ongoing arms race between websites and proxy users.</p>
<h2 id="heading-security-considerations-when-using-proxies"><strong>Security Considerations When Using Proxies</strong></h2>
<p>Not all proxies are trustworthy. When you route traffic through a proxy, that proxy can see your requests and responses. This means sensitive data should only be sent over encrypted connections.</p>
<p>Public or free proxies often log traffic, inject ads, or behave unpredictably. For serious use cases, dedicated or private proxies are safer.</p>
<p>In corporate environments, proxies are part of the security model. They enforce policies, block malicious destinations, and provide audit logs. In these cases, the proxy is a defensive tool rather than a privacy tool.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>A proxy is a simple but powerful concept. By inserting an intermediary between a client and the internet, proxies change how requests appear, how traffic is controlled, and how systems scale.</p>
<p>They are used for privacy, testing, automation, compliance, and performance. While they are often mentioned alongside VPNs, proxies offer more targeted control and flexibility, especially for developers and infrastructure teams.</p>
<p>Understanding how proxies work at a request level helps you decide when to use them, how to configure them safely, and how to design systems that rely on them. Whether you are building a scraper, testing geo-specific behavior, or managing outbound traffic, proxies remain a core building block of the modern internet.</p>
<p><em>Hope you enjoyed this article. Find me on</em> <a target="_blank" href="https://linkedin.com/in/manishmshiva"><em>Linkedin</em></a> <em>or</em> <a target="_blank" href="https://manishshivanandhan.com/"><em>visit my website</em></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use CDNs to Improve Performance in your Front-end Projects ]]>
                </title>
                <description>
                    <![CDATA[ In web development, styling plays a crucial role in the visual presentation of web applications. According to a study by Adobe, 59% of users would choose a beautifully designed website over a “simple and plain” design. So designs that are crafted in ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-cdns-improve-performance-in-front-end-projects/</link>
                <guid isPermaLink="false">670d72a6d4c1491e5ee9df77</guid>
                
                    <category>
                        <![CDATA[ Frontend Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CDN ]]>
                    </category>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Timothy Olanrewaju ]]>
                </dc:creator>
                <pubDate>Mon, 14 Oct 2024 19:36:06 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728820334493/8ef2738f-c2ac-42d3-be3f-5a6a3bddbdbd.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In web development, styling plays a crucial role in the visual presentation of web applications. According to a study by Adobe, 59% of users would choose a beautifully designed website over a “simple and plain” design. So designs that are crafted in a visually appealing way tend to attract users to consume content on a website.</p>
<p>In recent times, there has been a steady rise in styling tools that you can use to elevate the visual appeal of your websites. Such tools include CSS frameworks, animation libraries, icon libraries, and typography libraries. These tools offer customization flexibility, responsiveness, and consistency.</p>
<p>One awesome thing about these styling tools is that they bundle stylistic effects in a file which you can access via a Content Delivery Network (CDN).</p>
<p>In this article, we’ll be looking extensively at CDNs, how they work, their different hosting methods, the differences between them, their pros and cons, and the best use-cases of the methods for your project.</p>
<p>Let's dive straight into it!</p>
<h3 id="heading-what-well-cover">What we’ll cover:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-a-cdn">What is a CDN?</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-does-a-cdn-work">How does a CDN work?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-real-world-analogy-to-explain-cdns">Real-world analogy to explain CDNs</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-why-are-cdns-important">Why are CDNs Important?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-different-ways-to-use-a-cdn">Different Ways to Use a CDN</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-remote-hosted-cdn">Remote Hosted CDN</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-locally-hosted-cdn">Locally Hosted CDN</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-hybrid-hosted-cdn">Hybrid Hosted CDN</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-what-is-a-cdn"><strong>What is a CDN?</strong></h2>
<p>A CDN, or Content Delivery Network, is a system of distributed servers that delivers web content (like images, stylesheets, scripts and other resources) to users, reliably and efficiently.</p>
<h3 id="heading-how-does-a-cdn-work"><strong>How does a CDN work?</strong></h3>
<p>A CDN’s primary function is to cache and serve both static and dynamic web content to users. It achieves this by using the following:</p>
<ul>
<li><p><strong>Origin Server</strong>: This is the main server where all content is originally hosted.</p>
</li>
<li><p><strong>Edge Servers</strong>: These are servers distributed in different geographical locations to serve web content to users closer to them.</p>
</li>
<li><p><strong>Caching</strong>: This is a way of storing content on edge servers to reduce repeated requests to the origin server.</p>
</li>
<li><p><strong>DNS Routing</strong>: This is the mechanism that reroutes users to the nearest edge servers based on their location.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728819505243/6389ac39-e1d2-4348-9f97-8ee370eecd7f.png" alt="Diagram showing origin server communicating with different edge servers" class="image--center mx-auto" width="1600" height="900" loading="lazy"></p>
<p>This is what happens when a user clicks on a CDN link:</p>
<ul>
<li><p>If trying to access the resource for the first time, the request hits the origin server.</p>
</li>
<li><p>The origin server sends the resource to the user as a response and also sends a copy to the edge server located geographically closest to the user.</p>
</li>
<li><p>The edge server caches the copy.</p>
</li>
<li><p>When the user wants to access the resources again, the edge server (not the origin server) sends over the cached copy.</p>
</li>
</ul>
<h3 id="heading-real-world-analogy-to-explain-cdns"><strong>Real-World Analogy to Explain CDNs</strong></h3>
<p>To further explain how the CDN works, I’ll give an analogy to make it clearer. Imagine having an account with a bank that has its headquarters in New York (origin server).</p>
<p>You don’t expect customers who live far away from New York to be scampering to the headquarters any time they encounter issues. Instead, the bank provides branches (edge servers) in different locations to cater to the needs of their customers. Customers can easily walk into any branch nearest to them and get their issues or transactions sorted.</p>
<p>The branches have every customer's account information and transaction logs (cached data). Every branch of that bank delivers the same services and can satisfy their customers regardless of their distance from the headquarters.</p>
<p>The distribution of branches in different locations helps reduce the traffic that would have caused delays if the bank had just the headquarters as the only option. On contacting the bank's customer service on an issue, you would most likely be redirected to the nearest bank branch to you (DNS Routing)!</p>
<h2 id="heading-why-are-cdns-important"><strong>Why are CDNs Important?</strong></h2>
<p>There are many reasons why CDNs many websites use CDNs these days. Some of the key benefits are:</p>
<ol>
<li><p><strong>Improved Website Performance:</strong> CDNs can compress files and optimize images automatically, which helps speed up load time.</p>
</li>
<li><p><strong>Efficient Resource Storage:</strong> With CDNs, styling resources are stored and managed properly. Resources are also stored in files matching their content types.</p>
</li>
<li><p><strong>Better Search Engine Optimization (SEO):</strong> Using CDNs directly speeds up load time which in turn impacts search engine rankings. Google considers site speed a key metric that allows web pages to show up higher in search engines.</p>
</li>
<li><p><strong>Better User Experience:</strong> Users prefer faster and more responsive websites to slow and unresponsive ones. With a better user experience, a website is sure to receive more engagement and lower bounce rates.</p>
</li>
</ol>
<h2 id="heading-different-ways-to-use-a-cdn"><strong>Different Ways to Use a CDN</strong></h2>
<p>There are three ways you can access CDN resources in your project:</p>
<ul>
<li><p>Remote Hosting</p>
</li>
<li><p>Local Hosting</p>
</li>
<li><p>Hybrid Hosting</p>
</li>
</ul>
<h3 id="heading-remote-hosted-cdn"><strong>Remote Hosted CDN</strong></h3>
<p>Remote CDN links allow developers to access styling resources from a third-party server by simply linking to the CDN in their HTML files via the <code>link</code> or <code>script</code> tag.</p>
<p>Bootstrap, for example, has two primary CDN links – one for CSS stylesheet and another for JavaScript (handles dynamic interaction like dropdowns, pop-overs, and so on).</p>
<p>To use a Bootstrap stylesheet in your project, you need to add this single line - <code>https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css</code></p>
<p>And for the JavaScript: <code>https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js</code></p>
<h4 id="heading-how-to-find-remote-cdn-links"><strong>How to find remote CDN links</strong></h4>
<p>The best way to identify thte remote CDN links of your desired styling tool is to visit their official documentation site and look for the direct links there.</p>
<h4 id="heading-advantages-of-a-remote-cdn"><strong>Advantages of a remote CDN:</strong></h4>
<ol>
<li><p><strong>Easy to Use:</strong> You don’t need to download, manage, or upload files with CDN links. All you need to do is insert a single line of code in your HTML file and you are good to go.</p>
</li>
<li><p><strong>Global Caching:</strong> whenever you visit a website that uses CDN links, it downloads the resources on loading the page and then saves it in your browser cache. On subsequent visits to the same website or other sites that use the same CDN, it fetches from the cache and displays these resources more quickly. This is one of the biggest advantages of using CDN links, as it improves website load time.</p>
</li>
<li><p><strong>Optimized Global Delivery:</strong> CDNs are built to deliver content to users around the world by serving files from edge servers closest to users. This helps reduce the time it takes data to transfer across a network, also known as latency, and boosts performance for international users.</p>
</li>
<li><p><strong>Reduced Server Load:</strong> Due to the CDN fetching data from an external source, the load on your server is reduced, which is helpful for high-traffic websites.</p>
</li>
<li><p><strong>Real-Time Updates:</strong> Companies that own CDN links carry out periodic bug fixing, security patching, and feature updates, which can be beneficial for your project. These updates are reflected as soon as they are released.</p>
</li>
</ol>
<h4 id="heading-disadvantages-of-a-remote-cdn"><strong>Disadvantages of a remote CDN:</strong></h4>
<ol>
<li><p><strong>Customization Limitations:</strong> Styling components in remote CDNs are standard and unmodified. To modify them, you would have to override the specific styles in your local file which can introduce complexities.</p>
</li>
<li><p><strong>No Control over Updates:</strong> When automatic updates are made, they can cause problems in your web applications. If the changes being introduced include drastic changes, it can affect your website’s layout or behavior in a big way.</p>
</li>
<li><p><strong>Dependency on Third-Party Availability:</strong> If the CDN service experiences hitches like downtime or slowness, it can lead to broken styles thus, affecting your site’s performance negatively.</p>
</li>
<li><p><strong>Privacy and Security Concerns:</strong> Links referencing an external source can pose serious security concerns, as they can be used to track users and get vital information. It is important to include only trusted CDN link sources in your web project to avoid breaches.</p>
</li>
</ol>
<h3 id="heading-locally-hosted-cdn"><strong>Locally Hosted CDN</strong></h3>
<p>These are CDN resources downloaded from a remote CDN and saved within your project folder or hosted on a local server. This approach allows you to have full control over the resources.</p>
<h4 id="heading-how-to-host-cdn-resources-locally"><strong>How to host CDN resources locally:</strong></h4>
<p>Hosting locally is straightforward and easy. All you have to do is:</p>
<ul>
<li><p>Access the resource by navigating to the CDN link URL (for example, <a target="_blank" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"><code>https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css</code></a>).</p>
</li>
<li><p>Copy the code found in the URL.</p>
</li>
<li><p>Create a file with the appropriate file extension (.css, .js) within your project folder.</p>
</li>
<li><p>Paste and save.</p>
</li>
<li><p>Reference the file in your HTML document.</p>
</li>
</ul>
<p>If you follow these steps, you should be able to localize the CDN resource and access its styling locally.</p>
<h4 id="heading-advantages-of-a-locally-hosted-cdn"><strong>Advantages of a locally hosted CDN:</strong></h4>
<ol>
<li><p><strong>Full Control over Files:</strong> With resources resident within your project folder/server, you’re in full control of your files as there will be no unexpected outages, changes, or updates that might break your site.</p>
</li>
<li><p><strong>Offline Availability:</strong> Local hosting ensures that your styling resources are always available, especially for users with little or no network. This is perfect for building Progressive Web Applications (PWAs)<strong>.</strong></p>
</li>
<li><p><strong>Customization:</strong> There’s be no need for overrides, as your styling can be modified from within your project files.</p>
</li>
<li><p><strong>Security:</strong> By localizing CDN resources, you reduce the risk of potential third-party attacks on your project to the barest minimum.</p>
</li>
</ol>
<h4 id="heading-disadvantages-of-a-locally-hosted-cdn"><strong>Disadvantages of a locally hosted CDN:</strong></h4>
<ol>
<li><p><strong>No Global Caching:</strong> There is no benefit of global caching when resources are hosted locally. This will result in slower load time for first-time visitors.</p>
</li>
<li><p><strong>Increased Server Load:</strong> With files residing locally, the load on the server increases especially as traffic increases. This approach puts a burden on the server and its capacity has to be considered.</p>
</li>
<li><p><strong>Manual Updates:</strong> While hosting locally gives you control over updates, you’ll need to manually track and apply updates to your stylesheets when necessary. Also, missing security updates could make your site vulnerable.</p>
</li>
<li><p><strong>Regional Performance Impact:</strong> If your server is located in a specific region, users from faraway places may encounter slower load times because the content has to travel greater distances.</p>
</li>
</ol>
<h3 id="heading-hybrid-hosted-cdn"><strong>Hybrid Hosted CDN</strong></h3>
<p>This approach involves the combination of using both the remote link and local hosting of CDN resources. A hybrid approach – which involves using remote CDNs for core libraries and local hosting for custom stylesheets – may strike the perfect balance between performance and control.</p>
<h3 id="heading-best-approach-to-use"><strong>Best Approach to Use</strong></h3>
<p>The decision between remote and local hosting of of your CDN styling resources depends on factors such as project performance needs, user base, and security. Your choice should depend on the suitability of the approach to your project and should elevate the performance levels.</p>
<h4 id="heading-best-use-cases-for-a-remote-cdn"><strong>Best use-cases for a remote CDN:</strong></h4>
<ol>
<li><p><strong>Global User Base:</strong> If your website is to be accessed by a large, globally distributed audience, using the remote option would work best due to its performance and caching advantage.</p>
</li>
<li><p><strong>Fast Integration:</strong> In a situation where you want to develop and deploy a project in the shortest period of time, using the remote CDN link is quick and easy.</p>
</li>
<li><p><strong>Low-Traffic Website:</strong> Small projects such as portfolio sites and blogs are better served using a remote CDN link so as not to put a strain on the server. It also leads to easier implementation.</p>
</li>
</ol>
<h4 id="heading-best-use-cases-for-a-locally-hosted-cdn"><strong>Best use-cases for a locally hosted CDN:</strong></h4>
<ol>
<li><p><strong>High Security Needs:</strong> For applications that require tight security due to the sensitivity of their operations, hosting the CDN resources locally will reduce third-party risks and vulnerabilities.</p>
</li>
<li><p><strong>Offline Applications:</strong> For web applications that work offline, localizing styling resources would be the best option.</p>
</li>
<li><p><strong>Customization Requirements:</strong> If you need to create your tailored styling versions, hosting them locally is the best option.</p>
</li>
</ol>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>In this guide, you’ve learned what a CDN is, how you can host your CDN, and some of the benefits, drawbacks, and best use-cases for each approach.</p>
<p>Remote CDNs provide speed, convenience and reduced server load, while local hosting offers greater control, security, and customization options.</p>
<p>Ultimately, the best approach depends on your specific use case, audience, and priorities.</p>
<p>You can connect with me on <a target="_blank" href="https://www.linkedin.com/in/timothy-olanrewaju750/">LinkedIn</a> or <a target="_blank" href="https://x.com/SmoothTee_DC">X</a> for more frontend-related posts and articles.</p>
<p>See you on the next one!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Network File System – How to Confirm Your Application is Using NFS ]]>
                </title>
                <description>
                    <![CDATA[ I was tasked recently to find which of our processes was accessing an NFS share. During this process, I found that some tools are better adapted than others for the task. In this article, I want to share with you my findings. The whole process was fu... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-confirm-your-application-is-using-nfs/</link>
                <guid isPermaLink="false">66d8514139c4dccc43d4d4b6</guid>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Jose Vicente Nunez ]]>
                </dc:creator>
                <pubDate>Mon, 18 Sep 2023 06:54:37 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725458376947/86a9c2e5-a07d-4802-82e4-dd8c28aebbc5.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I was tasked recently to find which of our processes was accessing an NFS share. During this process, I found that some tools are better adapted than others for the task.</p>
<p>In this article, I want to share with you my findings. The whole process was fun and gave me ideas on how to use these tools to tackle similar problems in the future.</p>
<h2 id="heading-what-is-nfs">What is NFS?</h2>
<p>Network File System (NFS) is a distributed file system protocol that allows a user to access files over a computer network.</p>
<p>Please note that this is not a full tutorial on NFS. For that, please take a look at the following <a target="_blank" href="https://www.redhat.com/sysadmin/getting-started-nfs">tutorial</a>.</p>
<p>In this article, we will focus only on detecting access to a shared drive using several techiques as well setting up two servers and one client.</p>
<p>Also, I do use a different OS to set up both the server and the client, so instructions on how to do the task change a little bit.</p>
<h2 id="heading-how-to-set-up-a-nfs-server-and-client">How to Set Up a NFS Server and Client</h2>
<p>My lab setup has one NFS server and two clients:</p>
<p><img src="https://github.com/josevnz/tutorials/blob/main/docs/SpyOnNfs/NfsLayout.png?raw=true" alt="NfsLayout" width="600" height="400" loading="lazy"></p>
<p>On my setup, I will have three computers talking to each other. One of them will be the NFS server and the other two will be a client.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Machine</td><td>OS</td><td>Hardware</td><td>Mode</td></tr>
</thead>
<tbody>
<tr>
<td>OrangePi5</td><td>Ubuntu Armbian 23.8.1 jammy</td><td>Orange Pi 5</td><td>Server:/data</td></tr>
<tr>
<td>RaspberriPi</td><td>Debian 20.04.4 LTS (Focal Fossa)</td><td>Raspberry Pi 4 Model B Rev 1.4</td><td>Server:/var/log/suricata</td></tr>
<tr>
<td>Dmaf5</td><td>Fedora 37 (Workstation Edition)</td><td>AMD Ryzen 5 3550H with Radeon Vega Mobile Gfx</td><td>Client</td></tr>
</tbody>
</table>
</div><h3 id="heading-how-to-configure-the-server">How to Configure the Server</h3>
<p>I will prepare my OrangePI machine to be the NFS server. Do so, I will enter the following commands:</p>
<pre><code class="lang-shell">sudo apt-get update
sudo apt-get upgrade
sudo apt-get install nfs-kernel-server -y
sudo systemctl enable nfs-kernel-server.service --now
</code></pre>
<p>Next step is to tell the <a target="_blank" href="https://ubuntu.com/server/docs/service-nfs">server we want to share</a>.</p>
<p>For that, we will edit the <a target="_blank" href="https://www.man7.org/linux/man-pages/man5/exports.5.html">/etc/exports</a> file (<code>sudo vi /etc/exports history</code>):</p>
<pre><code class="lang-text">/data *(ro,all_squash,async,no_subtree_check)
</code></pre>
<p>Please check the man page to understand what these options mean.</p>
<p>In a nutshell, export /data:</p>
<ul>
<li><p>Is read-only</p>
</li>
<li><p>Maps IDs to anonymous ID</p>
</li>
<li><p>This option allows the NFS server to violate the NFS protocol and reply to requests before any changes made by that request have been committed to stable storage</p>
</li>
<li><p>This option disables subtree checking. It's the default.</p>
</li>
</ul>
<p>Now it is time to activate our shared directories:</p>
<pre><code class="lang-shell">root@orangepi5:~# sudo exportfs -a
root@orangepi5:~# sudo showmount -e
Export list for orangepi5:
/data (everyone)
</code></pre>
<p>I did something similar to the other host, raspberrypi:</p>
<pre><code class="lang-shell">root@raspberrypi:~# cat /etc/exports
# /etc/exports: the access control list for filesystems which may be exported
#        to NFS clients.  See exports(5).
#
/var/log/suricata *(ro,all_squash,async,no_subtree_check)
root@raspberrypi:~# showmount -e
Export list for raspberrypi:
/var/log/suricata *
</code></pre>
<h3 id="heading-how-to-configure-the-client">How to Configure the Client</h3>
<p>First thing is to confirm we can indeed see the shared mount points from our server:</p>
<pre><code class="lang-shell">(tutorials) [josevnz@dmaf5 SpyOnNfs]$ sudo showmount -e orangepi5
Export list for orangepi5:
/data raspberrypi,dmaf5
</code></pre>
<p>Data is shared with two machines – just what we expected.</p>
<p>Now, there are several ways to mount this drive. One of them is manually, another one is at startup, and the last one, my preferred one, is on demand.</p>
<h4 id="heading-how-to-set-up-the-automount-client-on-fedora-linux">How to Set Up the AutoMount Client on Fedora Linux</h4>
<p>First we <a target="_blank" href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/4/html/system_administration_guide/mounting_nfs_file_systems-mounting_nfs_file_systems_using_autofs">set the service</a>:</p>
<pre><code class="lang-shell">sudo dnf install -y autofs
sudo systemct enable autofs.service --now
</code></pre>
<p>Then we set this up, so we end mounting remote <code>/data</code> into local <code>/misc/data</code>. For that, sdd the following line to your <code>/etc/auto.master</code>:</p>
<pre><code class="lang-shell">[root@dmaf5 ~]# vi /etc/auto.misc
# After editing the file, adding our entry to the last line of the file ...
[root@dmaf5 ~]# cat /etc/auto.misc
#
# This is an automounter map and it has the following format
# key [ -mount-options-separated-by-comma ] location
# Details may be found in the autofs(5) manpage

cd              -fstype=iso9660,ro,nosuid,nodev :/dev/cdrom

data            -ro,soft,rsize=16384,wsize=16384 orangepi5:/data
suricata        -ro,soft,rsize=16384,wsize=16384 raspberrypi:/var/log/suricata
</code></pre>
<p>Restart the service one more time:</p>
<pre><code class="lang-shell">[root@dmaf5 ~]# systemctl enable autofs.service --now
</code></pre>
<p>And the smoke test:</p>
<pre><code class="lang-shell">[root@dmaf5 ~]# ls -l /misc/data
total 0
drwxrwxr-x. 1 root 1001 48 Apr  7 17:57 nexus
[root@dmaf5 ~]# ls /misc/suricata
certs       eve.json.7  files            http.log    stats.log.1     suricata.log.2        suricata-start.log.3  tls.log.4
core        fast.log    http-data.log    http.log.1  stats.log.2     suricata.log.3        suricata-start.log.4  tls.log.5
eve.json    fast.log.1  http-data.log.1  http.log.2  stats.log.3     suricata.log.4        suricata-start.log.5  tls.log.6
eve.json.1  fast.log.2  http-data.log.2  http.log.3  stats.log.4     suricata.log.5        suricata-start.log.6  tls.log.7
eve.json.2  fast.log.3  http-data.log.3  http.log.4  stats.log.5     suricata.log.6        suricata-start.log.7
eve.json.3  fast.log.4  http-data.log.4  http.log.5  stats.log.6     suricata.log.7        tls.log
eve.json.4  fast.log.5  http-data.log.5  http.log.6  stats.log.7     suricata-start.log    tls.log.1
eve.json.5  fast.log.6  http-data.log.6  http.log.7  suricata.log    suricata-start.log.1  tls.log.2
eve.json.6  fast.log.7  http-data.log.7  stats.log   suricata.log.1  suricata-start.log.2  tls.log.3
</code></pre>
<p>Now we are ready to play with our service.</p>
<h2 id="heading-how-to-create-a-python-program-that-reads-files-into-the-nfs-server">How to Create a Python Program that Reads Files into the NFS Server</h2>
<p>For our example, we want to determine if a Python application is reading data from this directory. This script has two features:</p>
<ul>
<li><p>Performs a one time read view of a file. This will teach us how to capture this type of scenerarios, when a file is not opened all the time.</p>
</li>
<li><p>And the script also follows updates on a file periodically.</p>
</li>
</ul>
<p>Here is how our test script looks like in action:</p>
<pre><code class="lang-shell">./scripts/test_script.py \
--quick_read /misc/data/nexus/log/jvm.log \
--follow /misc/suricata/eve.json \
--verbose
...
2023-09-10 14:48:22,889 &lt;dependency_failed type='leaf_type' ctxk='java/io/FileOutputStream' witness='java/net/SocketOutputStream' stamp='66511.794'/&gt;
2023-09-10 14:48:22,889 &lt;dependency_failed type='leaf_type' ctxk='java/io/FileOutputStream' witness='java/net/SocketOutputStream' stamp='66511.794'/&gt;
2023-09-10 14:48:22,889 &lt;dependency_failed type='leaf_type' ctxk='java/io/FileOutputStream' witness='java/net/SocketOutputStream' stamp='66511.794'/&gt;
2023-09-10 14:48:22,889 &lt;dependency_failed type='leaf_type' ctxk='java/io/FileOutputStream' witness='java/net/SocketOutputStream' stamp='66511.794'/&gt;
2023-09-10 14:48:22,889 &lt;dependency_failed type='leaf_type' ctxk='java/io/FileOutputStream' witness='java/net/SocketOutputStream' stamp='66511.794'/&gt;
2023-09-10 14:48:22,889 &lt;dependency_failed type='leaf_type' ctxk='java/io/FileOutputStream' witness='java/net/SocketOutputStream' stamp='66511.794'/&gt;
2023-09-10 14:48:22,889 &lt;dependency_failed type='leaf_type' ctxk='java/io/FileOutputStream' witness='java/net/SocketOutputStream' stamp='66511.794'/&gt;
2023-09-10 14:48:22,890 &lt;dependency_failed type='leaf_type' ctxk='java/io/FileOutputStream' witness='java/net/SocketOutputStream' stamp='66511.794'/&gt;
2023-09-10 14:48:22,890 &lt;dependency_failed type='unique_concrete_method' ctxk='java/io/ByteArrayOutputStream' x='java/io/ByteArrayOutputStream write ([BII)V' witness='sun/security/ssl/HandshakeOutStream' stamp='66511.855'/&gt;
2023-09-10 14:48:22,890 &lt;dependency_failed type='unique_concrete_method' ctxk='java/io/ByteArrayOutputStream' x='java/io/ByteArrayOutputStream write ([BII)V' witness='sun/security/ssl/HandshakeOutStream' stamp='66511.855'/&gt;
...
# Ctrl-C to exit
</code></pre>
<p>The code, written in Python, is pretty simple:</p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/env python</span>
<span class="hljs-string">"""
Simple script to simulate light activity on NFS drives
Author Jose Vicente Nunez (kodegeek.com@protonmail.com)
"""</span>
<span class="hljs-keyword">import</span> concurrent
<span class="hljs-keyword">import</span> os
<span class="hljs-keyword">import</span> time
<span class="hljs-keyword">from</span> concurrent.futures <span class="hljs-keyword">import</span> ThreadPoolExecutor, ALL_COMPLETED
<span class="hljs-keyword">from</span> pathlib <span class="hljs-keyword">import</span> Path
<span class="hljs-keyword">from</span> argparse <span class="hljs-keyword">import</span> ArgumentParser
<span class="hljs-keyword">import</span> logging

logging.basicConfig(format=<span class="hljs-string">'%(asctime)s %(message)s'</span>, encoding=<span class="hljs-string">'utf-8'</span>, level=logging.DEBUG)


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">forever_read</span>(<span class="hljs-params">the_file: Path, verbose: bool = False</span>):</span>
    <span class="hljs-keyword">for</span> line <span class="hljs-keyword">in</span> continuous_read(the_file=the_file):
        <span class="hljs-keyword">if</span> verbose:
            logging.warning(line.strip())


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">continuous_read</span>(<span class="hljs-params">the_file: Path</span>):</span>
    <span class="hljs-string">"""
    Continuously read the contents of file
    :param the_file:
    :return:
    """</span>
    <span class="hljs-keyword">with</span> open(the_file, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> file_data:
        file_data.seek(<span class="hljs-number">0</span>, os.SEEK_END)
        <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
            line = file_data.readline()
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> line:
                time.sleep(<span class="hljs-number">0.1</span>)
                <span class="hljs-keyword">continue</span>
            <span class="hljs-keyword">yield</span> line


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">quick_read</span>(<span class="hljs-params">the_file: Path, verbose: bool = False</span>):</span>
    <span class="hljs-string">"""
    Red the whole file and close it once done
    :param verbose:
    :param the_file:
    :return:
    """</span>
    <span class="hljs-keyword">with</span> open(the_file, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> file_data:
        <span class="hljs-keyword">for</span> line <span class="hljs-keyword">in</span> file_data:
            <span class="hljs-keyword">if</span> verbose:
                logging.warning(line.strip())


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    PARSER = ArgumentParser(description=__doc__)
    PARSER.add_argument(
        <span class="hljs-string">'--verbose'</span>,
        action=<span class="hljs-string">'store_true'</span>,
        default=<span class="hljs-literal">False</span>,
        help=<span class="hljs-string">'Enable verbose mode'</span>
    )
    PARSER.add_argument(
        <span class="hljs-string">'--quick_read'</span>,
        type=Path,
        required=<span class="hljs-literal">True</span>,
        help=<span class="hljs-string">'Read a file once'</span>
    )
    PARSER.add_argument(
        <span class="hljs-string">'--follow'</span>,
        type=Path,
        required=<span class="hljs-literal">True</span>,
        help=<span class="hljs-string">'Read a file continuously'</span>
    )
    OPTIONS = PARSER.parse_args()
    <span class="hljs-keyword">try</span>:
        <span class="hljs-keyword">with</span> ThreadPoolExecutor(max_workers=<span class="hljs-number">3</span>) <span class="hljs-keyword">as</span> tpe:
            futures = [
                tpe.submit(forever_read, OPTIONS.follow, OPTIONS.verbose),
                tpe.submit(quick_read, OPTIONS.quick_read, OPTIONS.verbose)
            ]
            concurrent.futures.wait(futures, return_when=ALL_COMPLETED)
    <span class="hljs-keyword">except</span> KeyboardInterrupt:
        <span class="hljs-keyword">pass</span>
</code></pre>
<p>Now, let's go over how we can see if our script is indeed accessing an NFS partition.</p>
<h3 id="heading-common-steps">Common steps</h3>
<p>First we need to learn where to look for. So on the machine, check for NFS in <code>/etc/fstab</code> (for mount points that are available since the machine was rebooted):</p>
<pre><code class="lang-shell">[root@dmaf5 ~]# rg -e 'rsize=' /etc/fstab
</code></pre>
<p>Then on the AutoMount files:</p>
<pre><code class="lang-shell">[root@dmaf5 ~]# rg -e 'rsize=' /etc/auto*
/etc/auto.misc
17:data            -ro,soft,rsize=16384,wsize=16384 orangepi5:/data
18:suricata        -ro,soft,rsize=16384,wsize=16384 raspberrypi:/var/log/suricata
</code></pre>
<p>The regular expressions are not exact science, but you get the idea what to look for next.</p>
<h3 id="heading-how-to-use-the-tools">How to Use the tools</h3>
<p>We need to confirm if there was access to any of the following partitions mounted over NFS:</p>
<ul>
<li><p><code>/misc/data</code></p>
</li>
<li><p><code>/misc/suricata</code></p>
</li>
</ul>
<p>Next, I will show you a set of tools that will make the task easier, each one of them with their own strength and limitations.</p>
<p>Starting with <a target="_blank" href="https://www.redhat.com/sysadmin/analyze-processes-lsof">lsof</a> and <a target="_blank" href="https://github.com/BurntSushi/ripgrep">ripgrep</a> combined.</p>
<h3 id="heading-how-to-use-lsof-and-rg-for-capturing-and-filtering">How to Use Lsof and rg for Capturing and Filtering</h3>
<pre><code class="lang-shell">[josevnz@dmaf5 docs]$ lsof -w -b| rg -e '/misc/data|/misc/suricata'
python    36509                 josevnz    3   unknown                           /misc/suricata/eve.json
python    36509 36510 python    josevnz    3   unknown                           /misc/suricata/eve.json
python    36509 36511 python    josevnz    3   unknown                           /misc/suricata/eve.json
</code></pre>
<p>I passed the <code>-b</code> option to lsof to avoid it from getting stuck, in case the <a target="_blank" href="https://access.redhat.com/solutions/2674">NFS handle is stale</a>.</p>
<p>A few things about lsof:</p>
<ul>
<li><p>If you are using Autofs, you should know than mount points eventually get un-mounted to save bandwidth. This can be problematic when trying to catch the access of a file that is only opened once.</p>
</li>
<li><p>The short-lived read didn't show up because the filehandle was closed after we inspected the process.</p>
</li>
<li><p>If you want to monitor ALL the processes on this machine, you may need to run as root. You can only inspect your own processes without special privileges.</p>
</li>
</ul>
<p>Still, lsof is a great tool to investigate.</p>
<p>Next strategy involves monitoring from the beginning, to catch the elusive short-read. We will use <a target="_blank" href="https://strace.io/">strace</a>.</p>
<h3 id="heading-how-to-use-strace">How to Use strace</h3>
<pre><code class="lang-shell">sudo dnf install -y strace
(tutorials) [josevnz@dmaf5 SpyOnNfs]$ strace -f ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json 2&gt;&amp;1| rg -e '/misc/data|/misc/suricata'
execve("./scripts/test_script.py", ["./scripts/test_script.py", "--quick_read", "/misc/data/nexus/log/jvm.log", "--follow", "/misc/suricata/eve.json"], 0x7ffd9ae29738 /* 46 vars */) = 0
execve("/home/josevnz/virtualenv/tutorials/bin/python", ["python", "./scripts/test_script.py", "--quick_read", "/misc/data/nexus/log/jvm.log", "--follow", "/misc/suricata/eve.json"], 0x7ffe269dbf88 /* 46 vars */) = 0
[pid 38241] openat(AT_FDCWD, "/misc/suricata/eve.json", O_RDONLY|O_CLOEXEC &lt;unfinished ...&gt;
[pid 38242] openat(AT_FDCWD, "/misc/data/nexus/log/jvm.log", O_RDONLY|O_CLOEXEC &lt;unfinished ...&gt;
</code></pre>
<p>The <code>openat(AT_FDCWD)</code> entries give away the two files our script is reading from NFS. But as you can tell this approach has some caveats:</p>
<ul>
<li><p>We are filtering the output. It is best to save the output to a file with 'tee' and then search there</p>
</li>
<li><p>It requires starting the process with strace from the beginning. Yes, you could do a 'strace -p $PID' to attach later to the process, but you risk missing short-lived reads</p>
</li>
</ul>
<p>Is there a different way? Time to move on to the next tool, <a target="_blank" href="https://www.wireshark.org/docs/man-pages/tshark.html">tshark</a> and see how to use a network capture to confirm access to the share.</p>
<h3 id="heading-how-to-use-tshark">How to Use tshark</h3>
<p>We can also capture the network traffic and filter out only NFS. <a target="_blank" href="https://ask.wireshark.org/question/3582/how-to-capture-filename-path-for-nfsv4-traffic-using-tshark/">It is not perfect</a>, but it may be sufficient.</p>
<p>First, find out which network interface is used to communicate with the NFS server. In my case it is easy – they all connected using a wired private network:</p>
<pre><code class="lang-shell">[josevnz@dmaf5 docs]$ ip --oneline address|rg -e 'eno|wlp'
3: eno1    inet 192.168.68.70/22 brd 192.168.71.255 scope global dynamic noprefixroute eno1\       valid_lft 4568sec preferred_lft 4568sec
4: wlp4s0    inet 192.168.1.95/24 brd 192.168.1.255 scope global dynamic noprefixroute wlp4s0\       valid_lft 3423sec preferred_lft 3423sec
4: wlp4s0    inet6 fe80::ac40:5365:7f09:a5d2/64 scope link noprefixroute \       valid_lft forever preferred_lft forever
</code></pre>
<p>For this example it is eno1 with IP address '192.168.68.70'. Then capture the traffic, and with some luck we will get the file path:</p>
<pre><code class="lang-shell">[root@dmaf5 ~]# tshark -i eno1 -Y "nfs"
Running as user "root" and group "root". This could be dangerous.
Capturing on 'eno1'
 ** (tshark:42326) 16:02:47.417145 [Main MESSAGE] -- Capture started.
 ** (tshark:42326) 16:02:47.417286 [Main MESSAGE] -- File: "/var/tmp/wireshark_eno1rEGxiu.pcapng"
   13 1.601197994 192.168.68.70 → 192.168.68.60 NFS 450 V4 Call GETATTR FH: 0x90ba4ee1  ; V4 Call GETATTR FH: 0x90ba4ee1
   14 1.601374466 192.168.68.70 → 192.168.68.60 NFS 258 V4 Call GETATTR FH: 0x90ba4ee1
   15 1.601395155 192.168.68.70 → 192.168.68.60 NFS 258 V4 Call GETATTR FH: 0x90ba4ee1
   16 1.602155254 192.168.68.60 → 192.168.68.70 NFS 310 V4 Reply (Call In 13) GETATTR
   17 1.602368826 192.168.68.60 → 192.168.68.70 NFS 554 V4 Reply (Call In 13) GETATTR  ; V4 Reply (Call In 14) GETATTR
   19 1.602515091 192.168.68.70 → 192.168.68.60 NFS 274 V4 Call READ StateID: 0xa902 Offset: 57552896 Len: 12288
   20 1.602557170 192.168.68.60 → 192.168.68.70 NFS 310 V4 Reply (Call In 15) GETATTR
   22 1.603156327 192.168.68.60 → 192.168.68.70 NFS 1730 V4 Reply (Call In 19) READ
   66 4.611124808 192.168.68.70 → 192.168.68.60 NFS 642 V4 Call GETATTR FH: 0x90ba4ee1  ; V4 Call GETATTR FH: 0x90ba4ee1  ; V4 Call GETATTR FH: 0x90ba4ee1
   67 4.611301059 192.168.68.70 → 192.168.68.60 NFS 258 V4 Call GETATTR FH: 0x90ba4ee1
   68 4.611809385 192.168.68.60 → 192.168.68.70 NFS 310 V4 Reply (Call In 66) GETATTR
   69 4.611887552 192.168.68.60 → 192.168.68.70 NFS 310 V4 Reply (Call In 66) GETATTR
   71 4.611976479 192.168.68.60 → 192.168.68.70 NFS 310 V4 Reply (Call In 66) GETATTR
   72 4.620685968 192.168.68.60 → 192.168.68.70 NFS 310 V4 Reply (Call In 67) GETATTR
   74 5.017200005 192.168.68.70 → 192.168.68.60 NFS 250 V4 Call GETATTR FH: 0x9419c00c
   75 5.017804843 192.168.68.70 → 192.168.68.59 NFS 242 V4 Call GETATTR FH: 0x314e720f
   76 5.017838787 192.168.68.60 → 192.168.68.70 NFS 310 V4 Reply (Call In 74) GETATTR
   77 5.018131217 192.168.68.70 → 192.168.68.60 NFS 326 V4 Call OPEN DH: 0x90ba4ee1/
   78 5.018711408 192.168.68.60 → 192.168.68.70 NFS 386 V4 Reply (Call In 77) OPEN StateID: 0x9984
   79 5.018855699 192.168.68.59 → 192.168.68.70 NFS 310 V4 Reply (Call In 75) GETATTR
   81 5.018980434 192.168.68.70 → 192.168.68.59 NFS 262 V4 Call GETATTR FH: 0xecd332cc
   82 5.019934959 192.168.68.59 → 192.168.68.70 NFS 310 V4 Reply (Call In 81) GETATTR
   83 5.020032853 192.168.68.70 → 192.168.68.59 NFS 262 V4 Call GETATTR FH: 0x261d4440
   84 5.020734032 192.168.68.59 → 192.168.68.70 NFS 310 V4 Reply (Call In 83) GETATTR
   85 5.020874175 192.168.68.70 → 192.168.68.59 NFS 330 V4 Call OPEN DH: 0xc9b4831b/
</code></pre>
<p>This is great, there is activity against two NFS servers, 192.168.68.59 and 192.168.68.60. But, is there a way to see the name of files?</p>
<p>tshark has a way to spit information by field. The problem is that NFS has lots of them:</p>
<pre><code class="lang-shell">[root@dmaf5 ~]# for field in $(tshark -G fields| cut -d'        ' -f3|rg -e '^nfs\.'); do echo "-e $field"; done|head -n 10
Running as user "root" and group "root". This could be dangerous.
-e nfs.unknown
-e nfs.svr4
-e nfs.knfsd_le
-e nfs.nfsd_le
-e nfs.knfsd_new
-e nfs.ontap_v3
-e nfs.ontap_v4
-e nfs.ontap_gx_v3
-e nfs.celerra_vnx
-e nfs.gluster
</code></pre>
<p>So, let's <a target="_blank" href="https://www.wireshark.org/docs/dfref/n/nfs.html">capture them</a> into a variable (<a target="_blank" href="https://wiki.wireshark.org/NFS_Preferences">also need to enable some options</a>):</p>
<pre><code class="lang-shell">[root@dmaf5 ~]# fields=$(for field in $(tshark -G fields| cut -d'       ' -f3|rg -e '^nfs\.'); do echo "-e $field"; done)
[root@dmaf5 ~]# tshark -i eno1 --enable-protocol nfs -o nfs.file_name_snooping:true -o nfs.file_full_name_snooping:true -T fields -E header=y -E separator=, -E quote=d $fields
Running as user "root" and group "root". This could be dangerous.
nfs.unknown,nfs.svr4,nfs.knfsd_le,nfs.nfsd_le,nfs.knfsd_new,nfs.ontap_v3,nfs.ontap_v4,nfs.ontap_gx_v3,n...
</code></pre>
<p>I managed to get the filename only once, then after interrupting and restarting the program I got no luck.</p>
<p>And yet no sign of the file name. The file handle was in the contents but this is not very useful if you want a quick way to see what was accessed.</p>
<p>Is there an easier way to do this? Sysdig may offer some answers.</p>
<h3 id="heading-how-to-use-sysdig">How to Use Sysdig</h3>
<p>While trying to find the elusive mount points, I stumbled into <a target="_blank" href="https://github.com/draios/sysdig">Sysdig</a>:</p>
<p>Sysdig instruments your physical and virtual machines at the OS level by installing into the Linux kernel and capturing system calls and other OS events. Sysdig uses <a target="_blank" href="https://en.wikipedia.org/wiki/DTrace">DTrace</a> to get access to the system kernel.</p>
<p>Sysdig also makes it possible to create trace files for system activity, similarly to what you can do for networks with tools like tcpdump and Wireshark.</p>
<p>I decided to use the latest version (<a target="_blank" href="https://github.com/draios/sysdig/releases/tag/0.33.1">0.33.1</a>) for Fedora 37 where my script is running):</p>
<pre><code class="lang-shell">sudo dnf install -y https://github.com/draios/sysdig/releases/download/0.33.1/sysdig-0.33.1-x86_64.rpm
# Wait a little bit, as a kernel module needs to be compiled and prepared...
Installed:
  bison-3.8.2-3.fc37.x86_64                    dkms-3.0.11-1.fc37.noarch          elfutils-libelf-devel-0.189-3.fc37.x86_64  flex-2.6.4-11.fc37.x86_64            kernel-devel-6.4.13-100.fc37.x86_64 
  kernel-devel-matched-6.4.13-100.fc37.x86_64  libzstd-devel-1.5.5-1.fc37.x86_64  m4-1.4.19-4.fc37.x86_64                    openssl-devel-1:3.0.9-1.fc37.x86_64  sysdig-0.33.1-1.x86_64              
  zlib-devel-1.2.12-5.fc37.x86_64
</code></pre>
<p>How easy is to probe out the script so it is indeed accessing the NFS mounted directories? Let's print three fields of interest and the name of the accesed file:</p>
<pre><code class="lang-shell"># `sysdig -l` will output every single field you can capture
[root@dmaf5 ~]# sysdig -p"%proc.cmdline,%fd.name" proc.name contains python and fd.name contains /misc
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/suricata/eve.json
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/suricata/eve.json
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/suricata/eve.json
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/suricata/eve.json
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/suricata/eve.json
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/suricata/eve.json
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/suricata/eve.json
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/suricata/eve.json
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/suricata/eve.json
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/data/nexus/log/jvm.log
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/data/nexus/log/jvm.log
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/data/nexus/log/jvm.log
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/data/nexus/log/jvm.log
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/data/nexus/log/jvm.log
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/data/nexus/log/jvm.log
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/data/nexus/log/jvm.log
...
</code></pre>
<p>What if you want to capture all the data, and filter later? One way to do it is capturing to a file:</p>
<pre><code class="lang-shell"># Capture for one minute...
[root@dmaf5 ~]# timeout --preserve-status 1m sysdig -w /tmp/sysdig.dump
[root@dmaf5 ~]# ls -lh /tmp/sysdig.dump
-rw-r--r--. 1 root root 32M Sep 10 19:03 /tmp/sysdig.dump
</code></pre>
<p>And then replay the contents, with filtering (replay doesn't need elevated privileges):</p>
<pre><code class="lang-shell">[root@dmaf5 ~]# sysdig -r /tmp/sysdig.dump -p"%proc.cmdline,%fd.name" proc.name contains python and fd.name contains /misc|sort -u
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/data/nexus/log/jvm.log
python ./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose,/misc/suricata/eve.json
</code></pre>
<p>Sysdig supports scripting, using the <a target="_blank" href="https://www.lua.org/">LUA language</a>. For example, it has a very convenient version of lsof:</p>
<pre><code class="lang-shell">[root@dmaf5 ~]# sysdig -cl|rg lsof
lsof            List (and optionally filter) the open file descriptors.
</code></pre>
<p>So let's use it:</p>
<pre><code class="lang-shell">[root@dmaf5 ~]# sysdig -c lsof|rg misc
automount           52410   52410   root    8       directory   /misc
automount           52410   52413   root    8       directory   /misc
automount           52410   52414   root    8       directory   /misc
automount           52410   52415   root    8       directory   /misc
automount           52410   52418   root    8       directory   /misc
automount           52410   52421   root    8       directory   /misc
python              75840   75840   josevnz 3       file        /misc/suricata/eve.json
python              75840   75841   josevnz 3       file        /misc/suricata/eve.json
python              75840   75842   josevnz 3       file        /misc/suricata/eve.json
</code></pre>
<p>What I liked about this tool:</p>
<ul>
<li><p>Can work with older kernels (like 4.xx)</p>
</li>
<li><p>Has a powerful expression language for filtering</p>
</li>
<li><p>Easy to learn and well documented</p>
</li>
<li><p>You can write your own scripts if you know LUA</p>
</li>
</ul>
<p>Before finishing up let's look at one more tool, BPF.</p>
<h3 id="heading-how-to-use-bpf-probe">How to Use BPF probe</h3>
<p>Originally Berkeley Packet Filter, is a kernel and user-space observability scheme for Linux.</p>
<p>The BPF is a <a target="_blank" href="https://www.linuxjournal.com/content/bpf-observability-getting-started-quickly">very powerful tool</a>, and this short article won't even scratch the surface.</p>
<p>Yes, this is huge. I'm learning this myself.</p>
<p>I found that the <a target="_blank" href="https://github.com/iovisor/bcc">bcc</a> repository has lots of ready to use scripts that we could use to track our NFS access, and even check for performance (you can find more examples <a target="_blank" href="https://github.com/iovisor/bpftrace">here</a>, and on the <a target="_blank" href="https://github.com/brendangregg/bpf-perf-tools-book/tree/master">BPF Performance Book repository</a>).</p>
<p>But it is more interesting to write tools yourself that monitor pretty much anything you want. For this tutorial, I will use some ready to use programs that use the traces to capture useful information.</p>
<p>As a first step, we will need to install a high level interpreter for our scripts. Again, on my Fedora Linux machine:</p>
<pre><code class="lang-shell">[josevnz@dmaf5 ~]$ sudo dnf install -y bpftrace.x86_64 bcc-tools.x86_64
# And check if the kernel has btf enabled
[josevnz@dmaf5 ~]$ ls -la /sys/kernel/btf/vmlinux
-r--r--r--. 1 root root 5635179 Sep 12 04:21 /sys/kernel/btf/vmlinux
</code></pre>
<p>On a separate terminal run again the NFS test script:</p>
<pre><code class="lang-shell">. ~/virtualenv/tutorials/bin/activate
cd SpyOnNfs/
./scripts/test_script.py --quick_read /misc/data/nexus/log/jvm.log --follow /misc/suricata/eve.json --verbose
</code></pre>
<p>You can trace all the files opened by a program, like top:</p>
<pre><code class="lang-shell">18:59:20 loadavg: 1.20 1.00 0.74 1/1175 28520

TID     COMM             READS  WRITES R_Kb    W_Kb    T FILE
28520   clear            2      0      60      0       R xterm-256color
28203   python           7      0      56      0       R eve.json
28347   filetop          2      0      15      0       R loadavg
824     systemd-oomd     2      0      8       0       R memory.swap.current
824     systemd-oomd     2      0      8       0       R memory.low
...
</code></pre>
<p>But it doesn't print the full path. It's more useful to ask a NFS snoop and see if one of our files shows up:</p>
<pre><code class="lang-shell">[josevnz@dmaf5 SuricataLog]$ sudo /usr/share/bcc/tools/nfsslower 1
# Commented out some warnings ...
Tracing NFS operations that are slower than 1 ms... Ctrl-C to quit
TIME     COMM           PID    T BYTES   OFF_KB   LAT(ms) FILENAME
19:02:25 python         28202  R 1460    62150       1.96 eve.json
19:02:28 python         28202  R 2446    62151       2.09 eve.json
19:02:31 python         28202  R 970     62154       1.99 eve.json
19:02:34 python         28202  R 3335    62155       2.43 eve.json
19:02:37 python         28202  R 4564    62158       1.84 eve.json
19:02:40 python         28202  R 5876    62162       1.89 eve.json
19:02:43 python         28202  R 4504    62168       1.61 eve.json
19:02:46 python         28202  R 3131    62173       1.92 eve.json
</code></pre>
<p>This is much better. Also, we can see than the latency is almost two milliseconds.</p>
<p>We can also monitor mount/ umount operations:</p>
<pre><code class="lang-shell">[josevnz@dmaf5 SuricataLog]$ sudo /usr/share/bcc/tools/mountsnoop 
# Commented out some warnings ...
2 warnings generated.
COMM             PID     TID     MNT_NS      CALL
mount.nfs        29012   29012   4026531841  mount("orangepi5:/data", "/misc/data", "nfs", MS_RDONLY, "sloppy,soft,rsize=16384,wsize=16384,vers=4.2,addr=192.168.68.59,clientaddr=192.168.68.68") = 0
</code></pre>
<p>This is good as well, we can see the activity over NFS we wanted to confirm.</p>
<h2 id="heading-next-steps">Next Steps</h2>
<p>You learned several tools and as you may have guessed, you can use them to snoop on more than just opened files on NFS.</p>
<p>It is always useful to know more than one tool. Sysdig has a special mention for being very versatile, powerful and yet easy to use. Also, it can be extended with scripts written in the LUA language.</p>
<p>BPF is another alternative and will give you incredible access to the kernel calls. Be prepared to spend time reading and learning how to use the tools.</p>
<p>The code for the scripts used on this tutorial can be obtained from my <a target="_blank" href="https://github.com/josevnz/tutorials/tree/main/docs/SpyOnNfs">GitHub repository: SpyOnNfs</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ TCP and UDP Protocols – Explained in Plain English ]]>
                </title>
                <description>
                    <![CDATA[ Did you know that it's thanks to the TCP and UDP protocols that the internet works? But what do these acronyms mean? Well, TCP stands for Transmission Control Protocol and UDP stands for User Datagram Protocol Ok, but what are they? Why are they usef... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/tcp-and-udp-protocols/</link>
                <guid isPermaLink="false">66ba5347154fcfa01a69956c</guid>
                
                    <category>
                        <![CDATA[ beginners guide ]]>
                    </category>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tiago Capelo Monteiro ]]>
                </dc:creator>
                <pubDate>Thu, 10 Aug 2023 22:19:30 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/pexels-pixabay-159304.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Did you know that it's thanks to the TCP and UDP protocols that the internet works?</p>
<p>But what do these acronyms mean?</p>
<p>Well, TCP stands for Transmission Control Protocol and UDP stands for User Datagram Protocol</p>
<p>Ok, but what are they? Why are they useful? Why is it thanks to these protocols that the internet works?</p>
<p>In this article, we'll start with a simple analogy to help you understand the ideas behind TCP and UDP. Then I'll explain how they work in plain English. Next we'll discuss why these protocols are important, and we'll understand their key differences.</p>
<h2 id="heading-what-are-tcp-and-udp-explained-with-an-analogy">What are TCP and UDP? Explained with an Analogy</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/letter.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Photo by Suzy Hazelwood from Pexels: https://www.pexels.com/photo/shallow-focus-of-letter-paper-1157151/</em></p>
<p>You can think about TCP and UDP in a similar way as you think about a mail service.</p>
<p>Just like a <strong>mail service</strong> sends <strong>letters</strong> to <strong>individuals, TCP and UDP</strong> send <strong>packets</strong> to <strong>computers</strong>.</p>
<p>Packets are just formatted units of data in bytes.</p>
<p>TCP works more like a registered mail service. With registered mail, the sender sends a parcel to a recipient, and they're notified when the parcel is delivered. The sender can also track the parcel if it is lost or delayed.</p>
<p>On the other hand, UDP is like a regular mail service. The sender sends a parcel without any confirmation of delivery. There is also no tracking or guarantee that the parcel is going to be delivered.</p>
<h2 id="heading-how-do-tcp-and-udp-work">How Do TCP and UDP Work?</h2>
<p>Both the UDP and TCP are protocols used to ensure that data is reliably and securely transmitted between devices over a network.</p>
<p>TCP creates a connection between the sender and receiver and then data is transmitted between packets.</p>
<p>TCP also ensures that all packets are delivered in order. Additionally, it has mechanisms for resending lost packets and managing flow control. </p>
<p>Meanwhile, UDP sends packets without establishing a connection. Because of this, packets can be lost or arrive out of order as there is no mechanism to request retransmission.</p>
<h2 id="heading-tcp-vs-udp-whats-the-difference">TCP vs UDP – What's the Difference?</h2>
<p>Both UDP and TCP were developed starting in the 1980s.</p>
<p>TCP is important in programming because it provides a reliable and secure way for devices to communicate with each other over a network.</p>
<p>Without TCP, it would be difficult for devices to communicate securely, and many of the applications that we use today would not exist.</p>
<p>For example email communication, file transfers, and online transactions would all be very difficult without TCP.</p>
<p>TCP is preferred for secure, ordered, and reliable data transmission, as well as for delivering large amounts of data with minimal delay and mitigating network congestion.</p>
<p>UDP is also important for connections that require a lot broadband where security is not an issue.</p>
<p>For example video streaming services, online gaming platforms, and IoT devices can all use UDP to transmit data.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>With these protocols, the internet can operate safely and devices can communicate with each other effectively.</p>
<p>These concepts are key to understand if you're interested in Computer Networking. If you want to learn more about networking, you can <a target="_blank" href="https://www.freecodecamp.org/news/computer-networking-how-applications-talk-over-the-internet/">read this tutorial</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Networking in Flutter By Building a Simple App ]]>
                </title>
                <description>
                    <![CDATA[ Almost all apps you use today run by accessing the internet. You can hardly find an app that runs without connecting to the internet.  The internet has become an integral part of our lives, as it solves one of the most critical problems we have to ha... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-networking-in-flutter/</link>
                <guid isPermaLink="false">66ba10e3228e16bed602a8a5</guid>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Mon, 15 May 2023 18:42:25 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/Networking-in-Flutter---Banner.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Almost all apps you use today run by accessing the internet. You can hardly find an app that runs without connecting to the internet. </p>
<p>The internet has become an integral part of our lives, as it solves one of the most critical problems we have to handle: data transfer. We're constantly either receiving or sending data to someone – whether it's a social media app, news app, or whatever type it may be, there's some form of data transfer. </p>
<p>Because of this, it's super important to learn networking if you're learning mobile app development. In this article I'll be explaining how to build a super simple mobile app that fetches data from internet and renders it on the app. </p>
<h2 id="heading-how-to-create-the-project">How to Create the Project</h2>
<p>Navigate to the folder where you want to create your project in the terminal and run the following command:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/5minslearn/Flutter-Boilerplate.git
</code></pre>
<p>Navigate to the Flutter-Boilerplate folder and run the <code>flutter pub get</code> command to install the dependencies. </p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> Flutter-Boilerplate/
flutter pub get
</code></pre>
<p>That's it. We've got our dependencies installed.</p>
<p>Open the project in Visual Studio Code by running the <code>code ./</code> command in the terminal.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-40.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create a Flutter app from boiler plate</em></p>
<p>Start your emulator/connect your device and press <code>F5</code> in VS Code to run your app.</p>
<p>At the moment, the app will just contain an empty screen as shown in the below screenshot. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-41.png" alt="Image" width="600" height="400" loading="lazy">
<em>Flutter app with empty screen</em></p>
<p>Let's build our networking app. </p>
<h2 id="heading-where-to-get-the-data">Where to Get the Data</h2>
<p>This is the most obvious question. If we were to fetch something from the internet and render, we need an API server exposing the data we need. But, most people cannot afford to do that for learning purposes. To overcome this, many people are offering free API services. </p>
<p>You can consume the data from their API services for learning purposes. But, we cannot validate the originality of the data, as most of them will be random. </p>
<p>In this tutorial, we'll be using the API exposed by <a target="_blank" href="https://sampleapis.com/">https://sampleapis.com/</a>. They expose an API endpoint that lists Coding Resources. The URL of the endpoint is <a target="_blank" href="https://api.sampleapis.com/codingresources/codingResources">https://api.sampleapis.com/codingresources/codingResources</a>. </p>
<p>In our app, we'll fetch the data from this endpoint and list them in our app. </p>
<h2 id="heading-install-the-dependencies">Install the Dependencies</h2>
<p>Let's install the dependencies we need to build this app. They are:</p>
<ol>
<li>The <code>http</code> package</li>
<li>The <code>url_launcher</code> package</li>
</ol>
<p>We'll use the <code>http</code> package to make a call to the API endpoint. And we'll use the <code>url_launcher</code> package to open a URL in an external browser. </p>
<p>Open the <code>pubspec.yml</code> file and add the following two packages in the dependencies section:</p>
<pre><code class="lang-bash">  http: ^0.13.6
  url_launcher: ^6.1.11
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-42.png" alt="Image" width="600" height="400" loading="lazy">
<em>Add dependencies</em></p>
<p>If you're using VS Code as your IDE, the dependencies will be installed automatically by saving this file. For the other IDEs, run <code>flutter pub get</code> on your project root folder to install the dependencies. </p>
<h2 id="heading-how-to-fetch-the-data-from-the-api">How to Fetch the Data from the API</h2>
<p>We got our dependencies ready. Let's make a request to our API and get the data. </p>
<p>Import the <code>http</code> package in the <code>lib/main.dart</code> file. </p>
<pre><code class="lang-bash">import <span class="hljs-string">'package:http/http.dart'</span> as http;
</code></pre>
<p>Initialize a list object in the <code>_MyHomePageState</code> class by adding the following code:</p>
<pre><code class="lang-dart"><span class="hljs-built_in">List</span> _resources = [];
</code></pre>
<p>Let’s write a method that makes a call to our API endpoint and decode them into a JSON object. </p>
<pre><code class="lang-dart">  <span class="hljs-keyword">void</span> _fetchResources() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">final</span> response = <span class="hljs-keyword">await</span> http.<span class="hljs-keyword">get</span>(<span class="hljs-built_in">Uri</span>.parse(
        <span class="hljs-string">'https://api.sampleapis.com/codingresources/codingResources'</span>));
    <span class="hljs-keyword">if</span> (response.statusCode == <span class="hljs-number">200</span>) {
      <span class="hljs-keyword">final</span> data = json.decode(response.body) <span class="hljs-keyword">as</span> <span class="hljs-built_in">List</span>;
      setState(() {
        _resources = data;
      });
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">throw</span> Exception(<span class="hljs-string">'Failed to load resources'</span>);
    }
  }
</code></pre>
<p>Paste the above code into the <code>MyHomePageState</code> class. In the above method, we’re making a call to the API endpoint (<a target="_blank" href="https://api.sampleapis.com/codingresources/codingResources">https://api.sampleapis.com/codingresources/codingResources</a>). From the response, we’re validating if it's successful in receiving the data by checking if its status code is <code>200</code> (and throwing an error if it’s not). We then decode the received data and save it in our app’s state. </p>
<p>You may notice an error after pasting the above code at the <code>json.decode</code> part. In order to decode JSON, we need import a <code>convert</code> package in our file. Add the following code at the top of the file:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'dart:convert'</span>;
</code></pre>
<p>The error should be gone now. </p>
<p>We have a method that makes a call to the API endpoint and saves the data in the state. Our next step is to trigger this method when we open the app. </p>
<p>We can do that by overriding the <code>initState</code> method. </p>
<pre><code class="lang-dart">  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> initState() {
    <span class="hljs-keyword">super</span>.initState();
    _fetchResources();
  }
</code></pre>
<p>Quoting from the Flutter <a target="_blank" href="https://api.flutter.dev/flutter/widgets/State/initState.html">documentation</a>, </p>
<blockquote>
<p>"<code>initState</code> is called when this object is inserted into the tree. The framework will call this method exactly once for each <a target="_blank" href="https://api.flutter.dev/flutter/widgets/State-class.html">State</a> object it creates."</p>
</blockquote>
<p>In the above code, we called our method <code>_fetchResources()</code> in the <code>initState()</code> method. </p>
<h2 id="heading-how-to-build-the-ui">How to Build the UI</h2>
<p>We got the list of items whenever we open the app. Our next step is to render them on the UI. </p>
<p>Copy the below code and replace it with the <code>build</code> method of the <code>_MyHomePageState</code> class. </p>
<pre><code class="lang-dart"><span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: _resources.isEmpty
            ? <span class="hljs-keyword">const</span> Center(
                child: CircularProgressIndicator(),
              )
            : ListView.builder(
                itemCount: _resources.length,
                itemBuilder: (context, index) {
                  <span class="hljs-keyword">final</span> resource = _resources[index];
                  <span class="hljs-keyword">return</span> InkWell(
                      onTap: () =&gt; {},
                      child: Card(
                          child: ListTile(
                        title: Text(resource[<span class="hljs-string">'description'</span>]),
                        subtitle: Text(resource[<span class="hljs-string">'url'</span>]),
                        leading: <span class="hljs-keyword">const</span> CircleAvatar(
                            backgroundImage: NetworkImage(
                                <span class="hljs-string">"https://images.unsplash.com/photo-1547721064-da6cfb341d50"</span>)),
                        trailing: Text(resource[<span class="hljs-string">'types'</span>].join(<span class="hljs-string">', '</span>)),
                      )));
                }));
  }
</code></pre>
<p>Let’s understand the above code. </p>
<p>We show a loader if our state has empty values. If it has some values in it, we’ll iterate through as a ListView builder and we render a card widget for each item, displaying the <code>description</code>, <code>url</code>, and <code>types</code> of the resource. </p>
<p>That’s it. </p>
<p>Run the app by pressing <code>F5</code> and you should be able to see the following: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-43.png" alt="Image" width="600" height="400" loading="lazy">
<em>Loading the resources</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-44.png" alt="Image" width="600" height="400" loading="lazy">
<em>Showing the resources</em></p>
<p>That’s awesome, isn’t it? </p>
<h2 id="heading-lets-fix-the-missing-part">Let's Fix the Missing Part</h2>
<p>But I feel there’s one small thing that’s missing at this point.</p>
<p>We’re able to see the list of the resources. But, we’re not able to view those resources. Some resources have a short link that we can easily remember and type. But, a few of them have a long URL which would be hard for a typical human being to remember. Let’s add a small enhancement that when we click on a resource, its link should be opened in our default browser. </p>
<p>This is very simple to implement in Flutter. This is the reason we added the <code>url_launcher</code> package at the beginning of this tutorial. </p>
<p>Import the <code>url_launcher</code> package in your app like this</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:url_launcher/url_launcher.dart'</span>;
</code></pre>
<p>Add the following method in the <code>_MyHomePageState</code> class:</p>
<pre><code class="lang-dart">_launchURL(<span class="hljs-built_in">String</span> url) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">await</span> canLaunch(url)) {
      <span class="hljs-keyword">await</span> launch(url);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">throw</span> <span class="hljs-string">'Could not launch <span class="hljs-subst">$url</span>'</span>;
    }
  }
</code></pre>
<p>The above method accepts a URL, validates the link, and opens it in the browser. </p>
<p>We have to call this method on tapping the card. We can achieve that by calling this method in the <code>onTap</code> property of the <code>InkWell</code> widget. </p>
<p>Here’s the code for it:</p>
<pre><code class="lang-dart">onTap: () =&gt; {_launchURL(resource[<span class="hljs-string">'url'</span>])},
</code></pre>
<p>Let’s run our app and test this. </p>
<p>You were likely disappointed on tapping a card – I certainly was while working on this. </p>
<p>You should have seen this error:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-45.png" alt="Image" width="600" height="400" loading="lazy">
<em>Error on opening a url: Exception has occurred. "Could not launch https://www.youtube.com/bocajs"</em></p>
<p>Though the URL is right, why is our system not opening this in a browser?</p>
<h2 id="heading-what-are-intent-actions">What are Intent Actions?</h2>
<p>Well, now we have to learn about intent actions. </p>
<p>Quoting it from Android Developers <a target="_blank" href="https://developer.android.com/reference/android/content/Intent">documentation</a>, </p>
<blockquote>
<p>"An Intent provides a facility for performing late runtime binding between the code in different applications. Its most significant use is in the launching of activities, where it can be thought of as the glue between activities. It is basically a passive data structure holding an abstract description of an action to be performed."</p>
</blockquote>
<p>This basically means that when we hand over something to the external app, we have to declare that in our app. For Android, we have to define it in <code>AndroidManifest.xml</code> and for iOS most of these configurations go into the <code>Info.plist</code> file. </p>
<p>Add the <code>queries</code> block in the following code to your <code>AndroidManifest.xml</code> file. </p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">manifest</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">application</span>&gt;</span>
        ...
    <span class="hljs-tag">&lt;/<span class="hljs-name">application</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">queries</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">intent</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">action</span> <span class="hljs-attr">android:name</span>=<span class="hljs-string">"android.intent.action.VIEW"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">category</span> <span class="hljs-attr">android:name</span>=<span class="hljs-string">"android.intent.category.BROWSABLE"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">data</span> <span class="hljs-attr">android:scheme</span>=<span class="hljs-string">"https"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">intent</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">queries</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">manifest</span>&gt;</span>
</code></pre>
<p>Uninstall the app from your mobile and run the app again. </p>
<p>Hopefully you should be able to see the link opened in the browser. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-46.png" alt="Image" width="600" height="400" loading="lazy">
<em>Link opened on a browser</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you’ve learned about networking in Flutter. We made a request to an API, rendered the list, and opened the URL in the browser. </p>
<p>This <a target="_blank" href="https://github.com/5minslearn/Flutter-Networking">repo</a> has my code. You can use it for your reference. </p>
<p>To learn more about Flutter, subscribe to my email newsletter on my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_networking">site</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_networking">https://5minslearn.gogosoon.com</a>) and follow me on social media. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Understanding VPC Architecture – How to Secure AWS EC2 Instances ]]>
                </title>
                <description>
                    <![CDATA[ AWS Virtual Private Clouds (VPCs) are the organizing structure of most AWS network operations. Without a clear understanding of how they work, it'll be hard to get security and efficiency quite right.  But before talking about VPCs directly, I'm goin... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/understanding-vpc-architecture-securing-aws-ec2-instances/</link>
                <guid isPermaLink="false">66b9965ca3099de4654e61b9</guid>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Cloud Computing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Clinton ]]>
                </dc:creator>
                <pubDate>Tue, 02 May 2023 13:33:22 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/pexels-sevenstorm-juhaszimrus-425160.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>AWS Virtual Private Clouds (VPCs) are the organizing structure of most AWS network operations. Without a clear understanding of how they work, it'll be hard to get security and efficiency quite right. </p>
<p>But before talking about VPCs directly, I'm going to take a minute or two to refresh your memories on the basics of TCP/IP networking architecture and NAT addressing. </p>
<p>But feel free to skip the next bit if you're already dug in on all that. When that's behind us, though, I'll show you what building VPCs in AWS looks like. </p>
<h2 id="heading-a-quick-tcpip-primer">A Quick TCP/IP Primer</h2>
<p>Ok. So TCP stands for Transmission Control Protocol and IP stands for Internet Protocol. If those sound a bit broad – almost as if they're trying to describe the totality of the internet – it's because just about everything we do on the internet is indeed controlled by these half century-old TCP/IP protocols.</p>
<p>This article comes from my <a target="_blank" href="https://www.udemy.com/course/securing-amazon-ec2-instances/?referralCode=E3ACB9DC5E3B77853E63">Securing Your AWS EC2 Instances course</a>. If you'd like, you can follow the video version here:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/iCal_Tzvg9g" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>For our purposes, remember that every network-connected device must have a unique IP address. Given that, mathematically, there can be no more than four billion 32-bit IPv4 addresses, and that there are already far more than four billion network-connected devices on the internet, something had to change. </p>
<pre><code>A typical IPv4 address:
<span class="hljs-number">192.168</span><span class="hljs-number">.2</span><span class="hljs-number">.45</span>
</code></pre><p>The 128-bit IPv6 protocol was eventually introduced to allow <em>trillions</em> of unique addresses. We'll never run out of those. </p>
<pre><code>A typical IPv6 address:
fd42:e265:<span class="hljs-number">3791</span>:<span class="hljs-number">64</span>f9:<span class="hljs-number">216</span>:<span class="hljs-number">3</span>eff:fe54:fcfe/<span class="hljs-number">64</span>
</code></pre><p>But before IPv6, another brilliant solution was introduced: NAT networking. </p>
<h2 id="heading-what-is-network-address-translation-nat">What is Network Address Translation (NAT)?</h2>
<p>The NAT protocol sets aside three network segments for use in <em>private</em> networks only. Using NAT, your home can have 15 or 20 devices – including laptops, smartphones on WiFi, network printers, routers, and maybe a smart fridge or two – but between them, they'll use up only a single public IP address. </p>
<p>How does that work? Well, your internet service provider will assign that one public IP to the modem they send you. But that modem will act as a DHCP server and assign each <em>local</em> device a <em>private</em> IP address from one of those three network segments. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/slide-31.png" alt="Image" width="600" height="400" loading="lazy">
<em>A typical NAT architecture</em></p>
<p>The DHCP server will <em>translate</em> all requests moving between your local devices and internet-based services in a way that leaves those internet services thinking that your device's IP is actually the single public one. </p>
<p>But incoming network packets are actually delivered right to your device using its local NAT address. The system really is brilliant. And it added decades of life to the IPv4 system.</p>
<p>But once we have NAT in place anyway, it can actually do a whole lot more than just translate local addressing. Which brings us to why we're talking about this stuff in the context of EC2 instance security in the first place. </p>
<p>You see, NAT allows for very sophisticated network segmenting. By carefully configuring addressing and routing rules, you can turn a single local network into a multi-layered, highly-secured environment for mission-critical enterprise deployments. </p>
<p>Here's an illustration of a replicated environment using public and private subnets from AWS documentation.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/bastion_aws.png" alt="Image" width="600" height="400" loading="lazy">
<em>How bastion hosts might fit into an AWS VPC</em></p>
<p>The only connection with the outside world, such a private subnet, would have flows through a bastion host and a NAT gateway living in an adjacent public subnet. Forcing everything through those two devices lets you precisely control traffic. </p>
<p>The bastion host provides a jump box allowing admins to safely open remote SSH sessions on instances running in your private subnets. And the NAT gateway allows services running on your private instances outbound access to, for example, pull software updates. Both bastion hosts and NAT gateways will incur regular usage costs, by the way.</p>
<h2 id="heading-how-to-optimize-vpc-networks">How to Optimize VPC Networks</h2>
<p>Now I'll show you how all this works within the AWS ecosystem. From the VPC dashboard I can click Create VPC. Right away I've got a decision to make: do I want to build just a simple VPC where I can host some resources, or something more complicated?</p>
<p>If I go with VPC only, I'll just need to give the VPC a name, select my addressing environments and I'm good to go. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/ec2_security8-f007434.png" alt="Image" width="600" height="400" loading="lazy">
<em>Part of the VPC configuration interface in AWS</em></p>
<p>But we're here to test drive the <em>VPC and more</em> option. As you can see, that'll open up an infrastructure preview to the right that shows us exactly what will be created based on the current selections, and what they'll look like. </p>
<p>Right now, as you can see, we'll get one public and one private subnet in each of two availability zones, and appropriate route tables and network connections to make everything work. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/ec2_security8-f007926.png" alt="Image" width="600" height="400" loading="lazy">
<em>Note how AWS automatically assigns logical names to new subnets</em></p>
<p>Note how each object is automatically given a name that properly reflects the naming structure I specified. All this automatically conforms with security and availability best-practices</p>
<p>I can choose to specify a dedicated tenancy for new instances launched into this VPC – although, as I mentioned earlier, that probably won't be relevant for all that many cases.</p>
<p>The number of availability zones you configure will reflect the depth of fault tolerance your application needs. The more zones, the less chance your application goes down. </p>
<p>Of course, by that same token, the more zones, the more instances you'll need to run and the more you'll spend. You can see that editing this value will have an instance impact on the subnet settings to the right.</p>
<p>You can similarly control the number of public and private subnets. The options available will reflect the number of availability zones you selected above. Basically, the UI makes it pretty much impossible to do something stupid – which is something I appreciate.</p>
<p>Adjusting the subnets within the UI will automatically update the configuration to the right. Selecting a NAT gateway will generate a new object with all the appropriate connectivity built-in. </p>
<p>One last really nice tool is the fields that let us fine tune the address allocation for our subnets. This could be important if you're planning to deploy, say, large numbers of virtual containers into a couple of public subnets but nothing more than a handful of database servers in your private subnets. You'll probably need a lot more addresses in the former and fewer in the latter.</p>
<p>Once you fire up your VPC, it'll take just a few seconds for all the parts to fall into place. When that's done, you'll be able to navigate to the Your VPCs dashboard to confirm what's now available. </p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>We covered a lot of ground in this article. You learned how VPCs can be designed to employ sophisticated routing topologies that expose and block resources to efficiently meet your operational and security needs.</p>
<p>Thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How Network Traffic is Routed ]]>
                </title>
                <description>
                    <![CDATA[ Moving around the internet – or even over a private local network – requires all kinds of magic wand waving and sorcery.  Or, in sightly more accurate terms, it requires the combination of sophisticated engineering and the existence of key standards,... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-network-traffic-is-routed/</link>
                <guid isPermaLink="false">66b995e694b336889c600432</guid>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Clinton ]]>
                </dc:creator>
                <pubDate>Wed, 19 Apr 2023 22:23:29 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/pexels-barry-tan-7994953.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Moving around the internet – or even over a private local network – requires all kinds of magic wand waving and sorcery. </p>
<p>Or, in sightly more accurate terms, it requires the combination of sophisticated engineering and the existence of key standards, including network ports, the domain Name System (DNS) and routing policies. And we're going to learn how some of that works in this article.</p>
<p>Besides IP addresses (identifiers that could look something like <code>192.168.2.54</code> or <code>e80::1164:3e06:6716:7a0b/64</code>), network traffic can be routed between devices or even individual services running on a device using TCP and UDP ports. </p>
<p>This article comes from <a target="_blank" href="https://www.udemy.com/course/complete-lpi-security-essentials-exam-study-guide/?referralCode=C2B6802EDB99578238B5">The Complete LPI Security Essentials Exam Study Guide</a>. You can also follow along using this video:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/GaTTrXcO13I" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-routing-network-traffic-using-network-ports">Routing Network Traffic Using Network Ports</h2>
<p>Ports are numbers used to identify specific applications or services running on a device. When data is transmitted over the network, the source and destination ports are included in the data packet to ensure that the data is sent to the correct application or service.</p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers">There are 65,535 TCP and UDP ports in total</a>, each of which can be assigned to a specific application or service for communication over the Internet. </p>
<p>The first 1024 ports are reserved for well-known services and are typically assigned to specific applications or services by the Internet Assigned Numbers Authority. For example, HTTP (Hypertext Transfer Protocol) uses port 80, while HTTPS (HTTP Secure) uses port 443.</p>
<p>The remaining ports (above 1024) are called ephemeral ports and can be used by any application or service that needs to communicate over the Internet. When a device initiates a connection, it selects an available ephemeral port to use for the duration of the connection.</p>
<p>Devices can also be identified by unique hardware Media Access Control addresses. MAC addresses – assigned at the link-layer of the OSI model – are used to identify devices on a local network segment and to provide a way for data to be transmitted directly to the correct device. Here's a typical MAC address:</p>
<pre><code><span class="hljs-number">40</span>:b0:<span class="hljs-number">72</span>:d4:<span class="hljs-number">29</span>:ab
</code></pre><h2 id="heading-what-is-the-domain-name-system-dns">What is the Domain Name System (DNS)?</h2>
<p>The Domain Name System is a system used to translate human-readable domain names into IP addresses. This allows users to access websites and other Internet resources using easy-to-remember domain names instead of IP addresses. </p>
<p>DNS also provides other important functions, such as mapping IP addresses to multiple domain names and directing traffic to the correct server based on the location of the user.</p>
<p>Forward DNS refers to the process of converting a domain name, such as "www.example.com", into an IP address, such as "192.0.2.1". Forward DNS is used by clients to resolve domain names to IP addresses, so that they can access websites, email servers, and other network services.</p>
<p>Reverse DNS, on the other hand, is the process of converting an IP address into a domain name. Reverse DNS is used to identify the domain name associated with a particular IP address. </p>
<p>This information can be used for security purposes, such as identifying the source of an incoming network connection, or for tracking the origin of spam or malicious traffic.</p>
<p>Public DNS servers are operated by organizations such as Google, Cloudflare, and OpenDNS, and are available for use by anyone on the Internet. Public DNS servers are often used as an alternative to the DNS servers provided by Internet Service Providers, as they can offer faster resolution times, better security features, and increased privacy.</p>
<h2 id="heading-hardware-routing-devices">Hardware Routing Devices</h2>
<p>From a hardware perspective, traffic routing is managed through a loosely related family of networking devices. It should be noted that a single device will sometimes come with features normally identified with more than one category. </p>
<ul>
<li>Switches allow multiple devices on a network to communicate with each other by forwarding data packets to the intended recipient. </li>
<li>Routers connect multiple networks together and forward data packets between them. Routers use routing tables to determine the best path for the data to take. </li>
<li>Access Points allow wireless devices to connect to a wired network. They act as a bridge between the wireless devices and the network router.</li>
</ul>
<p>It's useful to bear in mind that a "default router" is the gateway IP address used by devices on a network to communicate with devices on a different network. The default router is typically the IP address of the network router.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Understanding the software and hardware tools used to connect all of our many devices across digital networks can help you troubleshoot when things go wrong. But it's also a critical component for understanding the problems – and solutions – involved with network security.</p>
<p>This article and the accompanying video are excerpted from <a target="_blank" href="https://www.udemy.com/course/complete-lpi-security-essentials-exam-study-guide/?referralCode=C2B6802EDB99578238B5">my Complete LPI Security Essentials Exam Study Guide course</a>. And there's much more technology goodness available at <a target="_blank" href="https://bootstrap-it.com/">bootstrap-it.com</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is An ACL? Access Control Lists Explained ]]>
                </title>
                <description>
                    <![CDATA[ In computing, access control is the concept of limiting or regulating a person or machine's access to certain information or resources. One of the major mechanisms you use to do that is an access control list (ACL). An ACL is a set of rules for allow... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-deep-dive-into-access-control-lists/</link>
                <guid isPermaLink="false">66d45dd53a8352b6c5a2aa0b</guid>
                
                    <category>
                        <![CDATA[ Cloud Computing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chidiadi Anyanwu ]]>
                </dc:creator>
                <pubDate>Fri, 14 Apr 2023 14:43:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/towfiqu-barbhuiya-FnA5pAzqhMM-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In computing, access control is the concept of limiting or regulating a person or machine's access to certain information or resources.</p>
<p>One of the major mechanisms you use to do that is an access control list (ACL). An ACL is a set of rules for allowing or denying access to certain resources. Resources in this case may be files, networks, or devices.</p>
<p>In this article, we'll talk about what access control lists really are, and how you can use them. We're going to deal with:</p>
<ul>
<li><p>Filesystem ACLs and Network ACLs</p>
</li>
<li><p>Firewalls and stateful packet filtering</p>
</li>
<li><p>ACLs in Cloud Networking (Azure NSG, AWS SG, AWS NACL)</p>
</li>
<li><p>ACLs in DNS (BIND9)</p>
</li>
<li><p>ACLs in core networking (Cisco ACL types, Huawei ACL types)</p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To understand this article, you need a basic understanding of networking, firewalls, and cloud computing. You may particularly need to understand basic of <a target="_blank" href="https://www.linkedin.com/pulse/ip-addressing-chidiadi-anyanwu">IP addressing</a> and <a target="_blank" href="https://www.linkedin.com/pulse/dns-deep-dive-chidiadi-anyanwu/">DNS</a> concepts.</p>
<h2 id="heading-types-of-access-control-lists">Types of Access Control Lists</h2>
<p>When we talk about ACLs, many people just think of networks. But in fact, there are two types of ACLs:</p>
<ul>
<li><p>File system ACLs</p>
</li>
<li><p>Networking ACLs</p>
</li>
</ul>
<p>Filesystem ACLs help operating systems know what the user access privileges are for different files or directories in the system. NFSv4 ACLs and POSIX ACLs are examples of filesystem ACL types.</p>
<p>Networking ACLs are applied on interfaces and you use them to allow or deny traffic from certain sources or to certain destinations. This is what I'll be focusing on in this article.</p>
<h2 id="heading-structure-of-an-acl-rule">Structure Of An ACL Rule</h2>
<p>An ACL is like a group of rules identified by a name or number. An ACL rule usually has a priority number, the criteria (source address, destination address, and so on) and the allow/deny statement.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Cisco-ACL-structure.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Cisco ACL structure</em></p>
<h2 id="heading-firewalls-and-acls">Firewalls and ACLs</h2>
<p>A firewall is a security device or software that monitors the traffic going in and out of a device or network, and filters out unwanted or malicious traffic.</p>
<p>Until stateful packet inspection, ACLs were the major mechanism through which firewalls worked. With ACLs, packets are allowed and denied based on properties specified in the rules.</p>
<p>ACLs are stateless. You must create an inbound rule and a corresponding outbound rule, or else packets from one side might be blocked.</p>
<p>With stateful packet inspection (also known as dynamic packet filtering), you could then create security policies for a type of traffic. The firewall would establish a session whenever a packet is allowed, so that any response to that packet is allowed even though there was no specific policy to allow it.</p>
<p>This makes things easier and more efficient than using ACLs that are uni-directional. But it also means that more computing resources are utilized by the firewall and the network is slowed down.</p>
<p>Now, firewalls are a lot more complex than that with deep packet inspection (DPI), Intrusion Detection System (IDS)/Intrusion Prevention System (IPS) capabilities, and even antivirus capabilities, but those are outside the scope of this article.</p>
<p>Let's explore some networking situations where ACLs are used.</p>
<h2 id="heading-acls-in-cloud-networking">ACLs in Cloud Networking</h2>
<p>The major cloud service providers (CSPs) provide forms of ACLs or firewall capabilities for their customers to use in their cloud infrastructure.</p>
<p>For example, in Microsoft Azure, we have what is called Network Security Groups (NSG) and in AWS, we have Security Groups (SG) and the Network Access Control List (NACL). These are all implementations of ACL-like security.</p>
<h3 id="heading-aws">AWS</h3>
<p>An AWS security group determines what traffic is allowed to and from the resources attached to that security group. It consists of a list of inbound and outbound rules, and is stateful.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Screenshot--320--1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Default AWS Security Group</em></p>
<p>An AWS Network Access Control List is another list of rules but at the subnet level. The rules consist of the rule number, type, protocol, port range, source, destination and allow/deny fields. A NACL can be applied more than one subnet, but a subnet cannot be attached to more than one NACL.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Screenshot--319--nacl-3-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Inbound rules for AWS NACL</em></p>
<h3 id="heading-azure">Azure</h3>
<p>An Azure Network Security Group is a kind of firewall feature that works both at the subnet level and the network interface card (NIC) of the resources in your VNet. It is basically also a list of ACL rules consisting of priority number, name, port, protocol, source and destination.</p>
<p>Here, you can use IP addresses, service tags, or application security groups (ASGs) in the source and destination fields. NSGs are stateful.</p>
<p>Both the Azure NSG and the AWS NACL rules are very similar to the ACL rules used in core networking. Also, you cannot really refer to AWS Security Groups and Azure NSGs as ACLs because they're not stateless.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Microsoft-NSG-rules-image.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Azure NSG</em></p>
<h2 id="heading-acls-in-dns">ACLs in DNS</h2>
<p><a target="_blank" href="https://www.linkedin.com/pulse/dns-deep-dive-chidiadi-anyanwu/">DNS servers help resolve domain names to IP addresses</a>. If they accept and respond to requests from every device around them, it will impact their performance and make them susceptible to DDoS attacks. So, DNS administrators use ACLs to determine who can send DNS requests to the servers.</p>
<p>For example, in a BIND9 server, such an ACL will be defined in the named.conf file, and would look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/Screenshot--308--1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>An ACL in BIND9</em></p>
<h2 id="heading-acls-in-core-networking">ACLs in Core Networking</h2>
<p>This is a bit more complex than the other contexts we discussed above. ACLs on network devices are configured on the interfaces, and are used in many different scenarios. There are also different types of ACLs. By network devices, I mean devices like routers, switches, firewalls, access controllers, and so on.</p>
<p>Generally, these ACLs are identified by their names or ACL numbers, and their rules follow the format:</p>
<p><em>permit/deny criteria</em></p>
<p>For Cisco devices, there are two major types of IPv4 ACLs:</p>
<ul>
<li><p>Standard access lists</p>
</li>
<li><p>Extended access lists</p>
</li>
</ul>
<h3 id="heading-standard-acls">Standard ACLs</h3>
<p>These ACLs permit or deny traffic based on only the source IP address.</p>
<pre><code class="lang-python">R1(config)<span class="hljs-comment">#access-list 10 permit 192.168.17.0 0.0.0.255</span>
</code></pre>
<p>The rule above tells the router to permit packets from the <em>192,168,17,0/24</em> subnet. Note that <em>0.0.0.255</em> is not a subnet mask. It is a wildcard that tells the device to which extent it must match the address you entered. <em>255</em> means any number goes while <em>0</em> means it must match exactly.</p>
<p>So here, the network part <em>192.168.17</em> must be exactly the same in whatever packet, while the last octet (the host part) can be whatever. You can learn more about IP addressing <a target="_blank" href="https://www.linkedin.com/pulse/ip-addressing-chidiadi-anyanwu">here</a>.</p>
<h3 id="heading-extended-acls">Extended ACLs</h3>
<p>These ACLs permit or deny traffic based on what is known in networking as the 5-tuple (source address, destination address, source port, destination port, transport layer protocol).</p>
<pre><code class="lang-python">R2(config)<span class="hljs-comment">#access-list 100 permit tcp 10.1.1.0 0.0.0.255 host 10.2.2.2 eq 80</span>
</code></pre>
<p>The command above tells the router to permit any packet using the TCP transport layer protocol, coming from the 10.1.1.0/24 network to port 80 (<a target="_blank" href="https://www.linkedin.com/pulse/http-network-protocol-chidiadi-anyanwu/">HTTP</a>) of the host, 10.2.2.2.</p>
<p>The term 5-tuple in networking probably originated from mathematics. A tuple means a record/row. 5-tuple means a row with five columns – an ordered list of 5 elements.</p>
<p>The five elements we're mostly concerned with in networking when dealing with packets are the IP addresses (source and destination), port numbers (source and destination), and transport layer protocol. So, they're usually referred to as 5-tuple.</p>
<p>ACL numbers 1 - 99 and 1300 - 1999 denote standard ACLs while numbers 100 - 199 and 2000 - 2699 denote extended ACLs.</p>
<p>Many other vendors follow this pattern, but Huawei doesn't.</p>
<p>For Huawei devices, there are 5 types of IPv4 ACLs:</p>
<ul>
<li><p>Basic ACLs ( ACL numbers 2000 - 2999)</p>
</li>
<li><p>Advanced ACLs (ACL numbers 3000 - 3999)</p>
</li>
<li><p>Layer 2 ACLs (ACL numbers 4000 - 4999)</p>
</li>
<li><p>User-defined ACLs (ACL numbers 5000 - 5999)</p>
</li>
<li><p>User ACLs (ACL numbers 6000 - 6999)</p>
</li>
</ul>
<p><strong>Basic ACL:</strong> Permits or denies traffic based on source address. The ACL number ranges from 2000 - 2999.</p>
<p><strong>Advanced ACL:</strong> Permits or denies traffic based on the 5-tuple (source IP address, destination IP address, source port, destination port, and protocol type).</p>
<p><strong>Layer 2 ACL:</strong> Permits or denies traffic based on information in the frame header (source MAC address, destination MAC address, layer 2 protocol type).</p>
<p><strong>User-defined ACL:</strong> Permits or denies traffic based on packet headers, offsets, character string masks, and user defined character strings.</p>
<p><strong>User ACL:</strong> Permits or denies traffic based on source and destination IP addresses or user control list (UCL) groups, source and destination ports, and IPv4 protocol types.</p>
<pre><code class="lang-python">acl <span class="hljs-number">3500</span>                                                
 rule <span class="hljs-number">0</span> deny tcp source <span class="hljs-number">10.1</span><span class="hljs-number">.1</span><span class="hljs-number">.0</span> <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.255</span> destination <span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.9</span> <span class="hljs-number">0</span> destination-port eq <span class="hljs-number">80</span>                                                                
 rule <span class="hljs-number">5</span> allow tcp source <span class="hljs-number">10.1</span><span class="hljs-number">.1</span><span class="hljs-number">.0</span> <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.255</span> destination <span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.9</span> <span class="hljs-number">0</span> destination-port eq telnet
</code></pre>
<h3 id="heading-implicit-deny">Implicit deny</h3>
<p>It is also important to note that even if you do not add any rule at the end of your ACL, the last rule there is always a deny rule. It is not shown, so it is implicit. But it is there. It denies any packet that does not match any rule in your ACL.</p>
<h3 id="heading-a-few-things-to-know">A Few Things To Know</h3>
<p>ACL rules are executed sequentially, so if you have rule 3 and rule 5, rule 3 gets executed first.</p>
<p>It is always a good practice to create rules at intervals (rule 10, rule 20, rule 30) rather than just serially (rule 1, rule 2, rule 3). The reason is that you may want to add a rule in-between two existing rules, and you want the system to execute it in that particular order. It saves stress if there was space for that from the beginning.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Access control is critical to security. Digitally, ACLs have been the go-to mechanism for quick and easy access control. Though other methods like role-based access control (RBAC) and attribute-based access control (ABAC) have emerged, ACL still has its place in access control.</p>
<p>Thanks for reading. If you enjoyed this article, please share it so others can see it too.</p>
<p>You can also <a target="_blank" href="https://linkedin.com/in/chidiadi-anyanwu">connect with me on LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ HTTP Networking in JavaScript – Handbook for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ HTTP is the backbone of the modern internet. In this text-based course, you'll learn how the HTTP protocol works and how it's used in real-world web development. All the code samples for this course are in JavaScript, but the networking concepts you'... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/http-full-course/</link>
                <guid isPermaLink="false">66b9e9ec39e4436f19005afa</guid>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ http ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lane Wagner ]]>
                </dc:creator>
                <pubDate>Tue, 14 Feb 2023 00:42:39 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738338854008/9272a213-f1ed-40d0-8d33-f57a11b3756c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>HTTP is the backbone of the modern internet. In this text-based course, you'll learn how the HTTP protocol works and how it's used in real-world web development.</p>
<p>All the code samples for this course are in JavaScript, but the networking concepts you'll learn here apply generally to all coding languages. <em>If you're not familiar with JavaScript yet, you can check out</em> <a target="_blank" href="https://boot.dev/learn/learn-javascript"><em>my JS course here</em></a><em>.</em></p>
<p>I've included all the learning material you'll need here in this article, but if you would like a more hands-on experience, you can take the <a target="_blank" href="https://boot.dev/learn/learn-http">interactive version of this course with coding challenges on Boot.dev here.</a></p>
<p>I've also published a free video version of this course on the freeCodeCamp YouTube channel:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/2JYT5f2isg4" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<p>If you like this video, you can check out my other tutorials on my <a target="_blank" href="https://youtube.com/@bootdotdev">Boot.dev YouTube channel here</a>.</p>
<p>All that said, let's jump into learning about HTTP!</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-why-http">Why HTTP?</a></p>
</li>
<li><p><a class="post-section-overview" href="#What-is-dns">What is DNS?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-uris">What Are URIs?</a></p>
</li>
<li><p><a class="post-section-overview" href="#chapter-4-async-await">Async/Await</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-error-handling">Error Handling</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-http-headers">HTTP Headers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-json">What is JSON?</a></p>
</li>
<li><p><a class="post-section-overview" href="#chapter-8-http-methods">HTTP Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-url-paths-and-parameters">URL Paths and Parameters</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-https">What is HTTPs?</a></p>
</li>
</ol>
<h2 id="heading-why-http">Why HTTP?</h2>
<h3 id="heading-communicating-on-the-web">Communicating on the web</h3>
<p>Instagram would be pretty terrible if you had to manually copy your photos to your friend's phone when you wanted to share them. Modern applications need to be able to communicate information <em>between devices</em> over the internet.</p>
<ul>
<li><p>Gmail doesn't just store your emails in variables on your computer, it stores them on computers in their data centers.</p>
</li>
<li><p>You don't lose your Slack messages if you drop your computer in a lake – those messages exist on Slack's <a target="_blank" href="https://en.wikipedia.org/wiki/Web_server">servers</a>.</p>
</li>
</ul>
<h3 id="heading-how-does-web-communication-work">How does web communication work?</h3>
<p>When two computers communicate with each other, they need to use the same rules. An English speaker can't communicate verbally with a Japanese speaker, and similarly, two computers need to speak the same language to communicate.</p>
<p>This "language" that computers use is called a <a target="_blank" href="https://en.wikipedia.org/wiki/Communication_protocol">protocol</a>. The most popular protocol for web communication is <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview">HTTP</a>, which stands for Hypertext Transfer Protocol.</p>
<h3 id="heading-interacting-with-a-server">Interacting with a server</h3>
<p>In this course, a lot of the code samples will interact with the <a target="_blank" href="https://pokeapi.co/">PokeAPI</a>. It serves data about Pokémon.</p>
<p>Here's some code that retrieves a list of Pokémon from the PokeAPI:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> pokemonResp = <span class="hljs-keyword">await</span> getItemData()

logPokemons(pokemonResp.results)

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getItemData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://pokeapi.co/api/v2/pokemon/'</span>, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span>,
    <span class="hljs-attr">mode</span>: <span class="hljs-string">'cors'</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
    }
  })
  <span class="hljs-keyword">return</span> response.json()
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logPokemons</span>(<span class="hljs-params">pokemons</span>) </span>{
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> pokemon <span class="hljs-keyword">of</span> pokemons) {
    <span class="hljs-built_in">console</span>.log(pokemon.name)
  } 
}
</code></pre>
<p>When you run this code, you'll notice that none of the data that is logged to the console was generated within our code! That's because the data we retrieved is being sent over the internet from our servers via HTTP. Don't worry, we'll explain more about that later.</p>
<h3 id="heading-http-requests-and-responses">HTTP Requests and Responses</h3>
<p>At the heart of HTTP is a simple request-response system. The "requesting" computer, also known as the "<a target="_blank" href="https://en.wikipedia.org/wiki/Client_\(computing\)">client</a>", asks another computer for some information. That computer, the "<a target="_blank" href="https://en.wikipedia.org/wiki/Server_\(computing\)">server</a>" sends back a response with the information that was requested.</p>
<p><img src="https://i.imgur.com/ReFw6nN.png" alt="Image" width="925" height="297" loading="lazy"></p>
<p>We'll talk about the specifics of how the "requests" and "responses" are formatted later. For now, just think of it as a simple question-and-answer system.</p>
<ul>
<li><p>Request: "What are the items in the Fantasy Quest game?"</p>
</li>
<li><p>Response: A list of the items in the Fantasy Quest game</p>
</li>
</ul>
<h3 id="heading-http-powers-websites">HTTP powers websites</h3>
<p>As we discussed, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview">HTTP</a>, or Hypertext Transfer Protocol, is a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Protocol">protocol</a> designed to transfer information between computers.</p>
<p>There are other protocols for communicating over the internet, but HTTP is the most popular and is <em>particularly great for websites and web applications</em>.</p>
<p>Each time you visit a website, your browser is making an HTTP request to that website's server. The server responds with all the text, images, and styling information that your browser needs to render its pretty website.</p>
<p><img src="https://i.imgur.com/EflKJzq.jpg" alt="Image" width="1080" height="1080" loading="lazy"></p>
<h3 id="heading-http-urls">HTTP URLs</h3>
<p>A URL, or <a target="_blank" href="https://www.freecodecamp.org/news/url-definition/">Uniform Resource Locator</a>, is essentially the address of another computer, or "server" on the internet. Part of the URL specifies how to reach the server, and part of it tells the server what information we want - but more on that later.</p>
<p>For now, it's important to understand that a URL represents a piece of information on another computer that we want access to. We can get access to it by making a <em>request</em>, and reading the <em>response</em> that the server replies with.</p>
<h3 id="heading-how-to-use-urls-in-http">How to Use URLs in HTTP</h3>
<p>The <code>http://</code> at the beginning of a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_is_a_URL">website URL</a> specifies that the <code>http</code> protocol will be used for communication.</p>
<p><img src="https://i.imgur.com/6jiaXBn.png" alt="Image" width="368" height="137" loading="lazy"></p>
<p>Other communication protocols use URLs as well, (hence "Uniform Resource Locator"). That's why we need to be specific when we're making HTTP requests by prefixing the URL with <code>http://</code></p>
<h3 id="heading-requests-and-responses-review">Requests and Responses Review</h3>
<ul>
<li><p>A "client" is a computer making an HTTP request</p>
</li>
<li><p>A "server" is a computer responding to an HTTP request</p>
</li>
<li><p>A computer can be a client, a server, both, or neither. "Client" and "server" are just words we use to describe what computers are doing within a communication system.</p>
</li>
<li><p>Clients send requests and receive responses</p>
</li>
<li><p>Servers receive requests and send responses</p>
</li>
</ul>
<h2 id="heading-javascripts-fetch-api">JavaScript's Fetch API</h2>
<p>In this course, we'll be using JavaScript's built-in <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">fetch API</a> to make HTTP requests.</p>
<p>The <code>fetch()</code> function is made available to us by the JavaScript language running in the browser. All we have to do is provide it with the parameters it requires.</p>
<h3 id="heading-how-to-use-fetch"><strong>How to Use Fetch</strong></h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url, settings)
<span class="hljs-keyword">const</span> responseData = <span class="hljs-keyword">await</span> response.json()
</code></pre>
<p>We'll go in-depth on the various things happening in this standard <code>fetch</code> call later, but let's cover some basics for now.</p>
<ul>
<li><p><code>response</code> is the data that comes back from the server</p>
</li>
<li><p><code>url</code> is the URL we are making a request to</p>
</li>
<li><p><code>settings</code> is an object containing some request-specific settings</p>
</li>
<li><p>The <code>await</code> keyword tells JavaScript to wait until the request comes back from the server before continuing</p>
</li>
<li><p><code>response.json()</code> converts the response data from the server into a JavaScript object</p>
</li>
</ul>
<p>See if you can spot the issue with this code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> pokemonResp = getItemData()

logPokemons(pokemonResp.results)

<span class="hljs-comment">// the bug is above this line</span>

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getItemData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://pokeapi.co/api/v2/pokemon/'</span>, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span>,
    <span class="hljs-attr">mode</span>: <span class="hljs-string">'cors'</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
    }
  })
  <span class="hljs-keyword">return</span> response.json()
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logPokemons</span>(<span class="hljs-params">pokemons</span>) </span>{
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> pokemon <span class="hljs-keyword">of</span> pokemons) {
    <span class="hljs-built_in">console</span>.log(pokemon.name)
  } 
}
</code></pre>
<p>Hint: We're not waiting for the data to be sent back across the network.</p>
<h3 id="heading-web-clients">Web Clients</h3>
<p>A web client is a device making requests to a web server. A client can be any type of device but is often something users physically interact with. For example:</p>
<ul>
<li><p>A desktop computer</p>
</li>
<li><p>A mobile phone</p>
</li>
<li><p>A tablet</p>
</li>
</ul>
<p>In a website or web application, we call the user's device the "front-end".<br>A front-end client makes requests to a back-end server.</p>
<p><img src="https://i.imgur.com/zldXGet.jpg" alt="Image" width="1920" height="1080" loading="lazy"></p>
<h3 id="heading-web-servers">Web Servers</h3>
<p>Up to this point, most of the data you have worked with in your code has simply been generated and stored locally in variables.</p>
<p>While you'll always use variables to store and manipulate data while your program is running, most websites and apps use a web server to store, sort, and serve that data so that it sticks around for longer than a single session, and can be accessed by multiple devices.</p>
<h3 id="heading-listening-and-serving-data"><strong>Listening and serving data</strong></h3>
<p>Similar to how a server at a restaurant brings your food to the table, a <a target="_blank" href="https://en.wikipedia.org/wiki/Web_server">web server</a>) serves web resources, such as web pages, images, and other data. The server is turned on and "listening" for inbound requests constantly so that the second it receives a new request, it can send an appropriate response.</p>
<h3 id="heading-the-server-is-the-back-end">The server is the back-end</h3>
<p>While the "front-end" of a website or web application is the device the user interacts with, the "back-end" is the server that keeps all the data housed in a central location. If you're still confused, <a target="_blank" href="https://blog.boot.dev/backend/frontend-vs-backend-meaning/">check out this article comparing front-end and back-end development</a>.</p>
<h3 id="heading-a-server-is-just-a-computer">A server is just a computer</h3>
<p>"Server" is just the name we give to a computer that is taking on the role of serving data across a network connection.</p>
<p>A good server is turned on and available 24 hours a day, 7 days a week. While your laptop <em>can</em> be used as a server, it makes more sense to use a computer in a data center that's designed to be up and running constantly.</p>
<h2 id="heading-what-is-dns">What is DNS?</h2>
<h3 id="heading-web-addresses">Web Addresses</h3>
<p>In the real world, we use addresses to help us find where a friend lives, where a business is located, or where a party is being thrown.</p>
<p>In computing, web clients find other computers over the internet using <a target="_blank" href="https://en.wikipedia.org/wiki/Internet_Protocol">Internet Protocol or IP</a> addresses.</p>
<p>An IP address is a numerical label that serves two main functions:</p>
<ol>
<li><p>Location Addressing</p>
</li>
<li><p>Network Identification</p>
</li>
</ol>
<h3 id="heading-domain-names-and-ip-addresses">Domain names and IP Addresses</h3>
<p>Each device connected to the internet has a unique IP address. When we browse the internet, the domains we navigate to are all associated with a particular IP address.</p>
<p>For example, this Wikipedia URL points to a page about miniature pigs: <code>https://en.wikipedia.org/wiki/Miniature_pig</code><br>The <a target="_blank" href="https://en.wikipedia.org/wiki/Domain_Name_System">domain</a> portion of the URL is <code>en.wikipedia.org</code>. <code>en.wikipedia.org</code> converts to a specific IP address, and that IP address tells your computer exactly where to communicate with that Wikipedia page.</p>
<p>Cloudflare is a tech company that provides a cool public HTTP server that we can use to look up the IP address of any domain. Take a look at this sample code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchIPAddress</span>(<span class="hljs-params">domain</span>) </span>{
  <span class="hljs-keyword">const</span> resp = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://cloudflare-dns.com/dns-query?name=<span class="hljs-subst">${domain}</span>&amp;type=A`</span>, {
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'accept'</span>: <span class="hljs-string">'application/dns-json'</span>
    }
  })
  <span class="hljs-keyword">const</span> respObject = <span class="hljs-keyword">await</span> resp.json()
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> record <span class="hljs-keyword">of</span> respObject.Answer) {
    <span class="hljs-keyword">return</span> record.data
  }
  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>
}

<span class="hljs-keyword">const</span> domain = <span class="hljs-string">'api.boot.dev'</span>
<span class="hljs-keyword">const</span> ipAddress = <span class="hljs-keyword">await</span> fetchIPAddress(domain)
<span class="hljs-keyword">if</span> (!ipAddress) {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'something went wrong in fetchIPAddress'</span>)
} <span class="hljs-keyword">else</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`found IP address for domain <span class="hljs-subst">${domain}</span>: <span class="hljs-subst">${ipAddress}</span>`</span>)
}
</code></pre>
<p>To recap, a "domain name" is part of a URL. It's the part that tells the computer <em>where the server is located on the internet</em> by being converted into a numerical IP address.</p>
<p>We'll cover exactly how an IP address is used by your computer to find a path to the server in a later networking course. For now, it's just important to understand that an IP address is what your computer is using at a lower level to communicate on a network.</p>
<p>Deploying a real website to the internet is actually quite simple. It involves only a couple of steps:</p>
<ol>
<li><p>Create a server that hosts your website files and connect it to the internet</p>
</li>
<li><p>Acquire a domain name</p>
</li>
<li><p>Connect the domain name to the IP address of your server</p>
</li>
<li><p>Your server is accessible via the internet!</p>
</li>
</ol>
<p><img src="https://i.imgur.com/vjjPt2a.png" alt="Image" width="310" height="163" loading="lazy"></p>
<p>As we discussed, the "domain name" or "hostname" is part of a URL. We'll get to the other parts of a URL later.</p>
<p>For example, the URL <code>https://example.com/path</code> has a hostname of <code>example.com</code>. The <code>https://</code> and <code>/path</code> portions are not part of the <code>domain name -&gt; IP address</code> mapping that we've been learning about.</p>
<h3 id="heading-using-the-url-api-in-javascript">Using the URL API in JavaScript</h3>
<p>The <code>URL</code> API is built into JavaScript. You can create a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">new URL object</a> like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> urlObj = <span class="hljs-keyword">new</span> URL(<span class="hljs-string">'https://example.com/example-path'</span>)
</code></pre>
<p>And then you can <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/URL">extract just the hostname</a>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> urlObj.hostname
</code></pre>
<h3 id="heading-dns-review">DNS Review</h3>
<p>So we've talked about domain names and what their purpose is, but we haven't talked about the system that's used to do that conversion.</p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/what-is-dns/">DNS</a>, or the "Domain Name System", is the phonebook of the internet. Humans connect to websites through <a target="_blank" href="https://en.wikipedia.org/wiki/Domain_name">domain names</a>, like <a target="_blank" href="https://boot.dev">Boot.dev</a>.</p>
<p>DNS "resolves" these domain names to find the associated <a target="_blank" href="https://en.wikipedia.org/wiki/Internet_Protocol">IP addresses</a> so that web clients can load the resources for the specific address.</p>
<p><img src="https://i.imgur.com/yvfSbVL.png" alt="Image" width="1024" height="512" loading="lazy"></p>
<h3 id="heading-how-does-dns-work">How does DNS Work?</h3>
<p>We'll go into more detail on DNS in a future course, but to give you a simplified idea of how it works, let's introduce ICANN. <a target="_blank" href="https://www.icann.org/">ICANN</a> is a not-for-profit organization that manages DNS for the entire internet.</p>
<p>Whenever your computer attempts to resolve a domain name, it contacts one of ICANN's "<a target="_blank" href="https://en.wikipedia.org/wiki/Root_name_server">root nameservers</a>" whose address is included in your computer's networking configuration.</p>
<p>From there, that nameserver can gather the domain records for a specific domain name from their distributed DNS database.</p>
<p>If you think of DNS as a phonebook, ICANN is the publisher that keeps the phonebook in print and available.</p>
<h3 id="heading-subdomains">Subdomains</h3>
<p>We learned about how a domain name resolves to an IP address, which is just a computer on a network - often the internet.</p>
<p>A subdomain prefixes a domain name, allowing a domain to route network traffic to many different servers and resources.</p>
<p>For example, the <a target="_blank" href="https://boot.dev">Boot.dev</a> website is hosted on a different computer than our blog. Our blog, found at <a target="_blank" href="https://blog.boot.dev">blog.boot.dev</a> is hosted on our "blog" subdomain.</p>
<h2 id="heading-what-are-uris">What are URIs?</h2>
<p>We briefly touched on URLs earlier, but now let's dive a little deeper into the subject.</p>
<p>A <a target="_blank" href="https://en.wikipedia.org/wiki/Uniform_Resource_Identifier">URI</a>, or Uniform Resource <em>Identifier</em>, is a unique character sequence that identifies a resource that is (almost always) accessed via the internet.</p>
<p>Just like JavaScript has syntax rules, so do URIs. These rules help ensure uniformity so that any program can interpret the meaning of the URI in the same way.</p>
<p>URIs come in two main types:</p>
<ul>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/URL">URLs</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Uniform_Resource_Name">URNs</a></p>
</li>
</ul>
<p>We will focus specifically on URLs in this course, but it's important to know that URLs are only one kind of URI.</p>
<p><img src="https://i.imgur.com/VzqzckC.png" alt="Image" width="500" height="394" loading="lazy"></p>
<p>URLs have quite a few sections, some of which are required, others not.<br>Let's use the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">URL API</a> to parse a URL and print all the different parts. We'll learn more about each part later, for now, let's just split and print a URL.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">printURLParts</span>(<span class="hljs-params">urlString</span>) </span>{
  <span class="hljs-keyword">const</span> urlObj = <span class="hljs-keyword">new</span> URL(urlString)
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`protocol: <span class="hljs-subst">${urlObj.protocol}</span>`</span>)
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`username: <span class="hljs-subst">${urlObj.username}</span>`</span>)
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`password: <span class="hljs-subst">${urlObj.password}</span>`</span>)
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`hostname: <span class="hljs-subst">${urlObj.hostname}</span>`</span>)
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`port: <span class="hljs-subst">${urlObj.port}</span>`</span>)
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`pathname: <span class="hljs-subst">${urlObj.pathname}</span>`</span>)
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`search: <span class="hljs-subst">${urlObj.search}</span>`</span>)
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`hash: <span class="hljs-subst">${urlObj.hash}</span>`</span>)
}

<span class="hljs-keyword">const</span> fantasyQuestURL = <span class="hljs-string">'http://dragonslayer:pwn3d@fantasyquest.com:8080/maps?sort=rank#id'</span>
printURLParts(fantasyQuestURL)
</code></pre>
<h3 id="heading-further-dissecting-a-url">Further dissecting a URL</h3>
<p>There are 8 main parts to a URL, though not all the sections are always present. Each piece plays a specific role in helping clients locate the specified resource.<br>The 8 sections are:</p>
<p><img src="https://i.imgur.com/iI3sUVh.png" alt="Image" width="1280" height="720" loading="lazy"></p>
<ul>
<li><p>The protocol is required</p>
</li>
<li><p>Usernames and passwords are optional</p>
</li>
<li><p>A domain is required</p>
</li>
<li><p>The default port for a given protocol is used if one is not provided</p>
</li>
<li><p>The default ( <code>/</code> ) path is used if one isn't provided</p>
</li>
<li><p>A query is optional</p>
</li>
<li><p>A fragment is optional</p>
</li>
</ul>
<h3 id="heading-dont-get-too-hung-up-on-memorizing-this-stuff">Don't get too hung up on memorizing this stuff</h3>
<p>Because names for the different sections are often used interchangeably, and because not all the parts of the URL are always present, it can be hard to keep things straight.</p>
<p>Don't worry about memorizing this stuff! Try to just get familiar with these URL concepts from a high level. Like any good developer, you can just look it up again the next time you need to know more.</p>
<h3 id="heading-the-protocol">The Protocol</h3>
<p>The "protocol", also referred to as the "scheme", is the first component of a URL. Its purpose is to define the rules by which the data being communicated is displayed, encoded, or formatted.</p>
<p>Some examples of different URL protocols:</p>
<ul>
<li><p>http</p>
</li>
<li><p>ftp</p>
</li>
<li><p>mailto</p>
</li>
<li><p>https</p>
</li>
</ul>
<p>For example:</p>
<ul>
<li><p><code>http://example.com</code></p>
</li>
<li><p><code>mailto:noreply@fantasyquest.app</code></p>
</li>
</ul>
<h3 id="heading-not-all-schemes-require-a">Not all schemes require a "//"</h3>
<p>The "http" in a URL is always followed by <code>://</code>. All URLs have the colon, but the <code>//</code> part is only included for schemes that have an <a target="_blank" href="https://www.rfc-editor.org/rfc/rfc3986#section-3.2">authority component</a>.</p>
<p>As you can see above, the <code>mailto</code> scheme doesn't use an authority component, so it doesn't need the slashes.</p>
<h3 id="heading-url-ports">URL Ports</h3>
<p>The port in a URL is a virtual point where network connections are made. Ports are managed by a computer's operating system and are numbered from <code>0</code> to <code>65,535</code>.</p>
<p>Whenever you connect to another computer over a network, you're connecting to a specific port on that computer, which is being listened to by a specific piece of software on that computer. A port can only be used by one program at a time, which is why there are so many possible ports.</p>
<p>The port component of a URL is often not visible when browsing normal sites on the internet, because 99% of the time you're using the default ports for the HTTP and HTTPS schemes: <code>80</code> and <code>443</code>, respectively.</p>
<p>Whenever you aren't using a default port, you need to specify it in the URL. For example, port <code>8080</code> is often used by web developers when they're running their server in "test mode" so that they don't use the "production" port "80".</p>
<p><img src="https://i.imgur.com/h3kBsRC.png" alt="Image" width="625" height="129" loading="lazy"></p>
<h3 id="heading-url-paths">URL Paths</h3>
<p>In the early days of the internet, a URL's path often was a reflection of the file path on the server to the resource the client was requesting.</p>
<p>For example, if the website <code>https://exampleblog.com</code> had a web server running within its <code>/home</code> directory, then a request to the <code>https://exampleblog.com/site/index.html</code> URL might expect the <code>index.html</code> file from within the <code>/home/site</code> directory to be returned.</p>
<p>Websites used to be very simple. They were just a collection of text documents stored on a server. A simple piece of server software could handle incoming HTTP requests and respond with the documents according to the path component of the URLs.</p>
<h3 id="heading-these-days-its-not-always-about-the-filesystem">These days, it's not always about the filesystem</h3>
<p>On many modern web servers, a URL's path isn't a reflection of the server's filesystem hierarchy. Paths in URLs are essentially just another type of parameter that can be passed to the server when making a request.</p>
<p>Conventionally, two different URL paths should denote different resources. For example, different pages on a website, or maybe different data types from a game server.</p>
<h3 id="heading-query-parameters">Query parameters</h3>
<p>Query parameters in a URL are <em>not</em> always present. In the context of websites, query parameters are often used for marketing analytics or for changing a variable on the web page. With website URLs, query parameters <em>rarely</em> change <em>which</em> page you're viewing, though they often will change the page's <em>contents</em>.</p>
<p>That said, query parameters can be used for anything the server chooses to use them for, just like the URL's path.</p>
<h3 id="heading-how-google-uses-query-parameters">How Google uses query parameters</h3>
<ol>
<li><p>Open a new tab and go to <a target="_blank" href="https://google.com">google.com</a></p>
</li>
<li><p>Search for "hello world"</p>
</li>
<li><p>Take a look at your current URL. It should start with <code>https://www.google.com/search?q=hello+world</code></p>
</li>
<li><p>Change the URL to say <code>https://www.google.com/search?q=hello+universe</code></p>
</li>
<li><p>Press "enter"</p>
</li>
</ol>
<p>You should see new search results for the query "hello universe". Google chose to use query parameters to represent the value of your search query. It makes sense - each search result page is <em>essentially</em> the same page as far as structure and formatting are concerned - it's just showing you different results based on the search query.</p>
<h2 id="heading-asyncawait">Async/Await</h2>
<p>You're probably already familiar with <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Synchronous">synchronous</a> code, which means code that <em>runs in sequence</em>. Each line of code executes in order, one after the next.</p>
<p><img src="https://i.imgur.com/03FFGu0.png" alt="Image" width="587" height="335" loading="lazy"></p>
<p>Example of synchronous code:</p>
<pre><code class="lang-js"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">"I print first"</span>);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"I print second"</span>);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"I print third"</span>);
</code></pre>
<p>Asynchronous or <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Asynchronous">async</a> code runs in <em>parallel</em>. That means code further down runs <em>at the same time that</em> a previous line of code is still running. A good way to visualize this is with the JavaScript function <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/setTimeout">setTimeout()</a>.</p>
<p><code>setTimeout</code> accepts a function and a number of milliseconds as inputs. It waits until the number of milliseconds has elapsed, and then it executes the function it was given.</p>
<p>Example of asynchronous code:</p>
<pre><code class="lang-js">jsconsole.log(<span class="hljs-string">"I print first"</span>);
<span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"I print third because I'm waiting 100 milliseconds"</span>), <span class="hljs-number">100</span>);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"I print second"</span>);
</code></pre>
<p>Try altering the waiting times in the async code below to get the messages to print in the proper order:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> craftingCompleteWait = <span class="hljs-number">0</span>
<span class="hljs-keyword">const</span> combiningMaterialsWait = <span class="hljs-number">0</span>
<span class="hljs-keyword">const</span> smeltingIronBarsWait = <span class="hljs-number">0</span>
<span class="hljs-keyword">const</span> shapingIronWait = <span class="hljs-number">0</span>

<span class="hljs-comment">// Don't touch below this line</span>

<span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Iron Longsword Complete!'</span>), craftingCompleteWait)
<span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Combining Materials...'</span>), combiningMaterialsWait)
<span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Smelting Iron Bars...'</span>), smeltingIronBarsWait)
<span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Shaping Iron...'</span>), shapingIronWait)

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Firing up the forge...'</span>)

<span class="hljs-keyword">await</span> sleep(<span class="hljs-number">2500</span>)
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sleep</span>(<span class="hljs-params">ms</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(resolve, ms))
}
</code></pre>
<p>Expected order:</p>
<ol>
<li><p>Firing up the forge..</p>
</li>
<li><p>Smelting Iron Bars...</p>
</li>
<li><p>Combining Materials...</p>
</li>
<li><p>Shaping Iron...</p>
</li>
<li><p>Iron Longsword Complete!</p>
</li>
</ol>
<h3 id="heading-why-do-we-want-async-code">Why do we want async code?</h3>
<p>We try to keep most of our code synchronous because it's easier to understand, and therefore often has fewer bugs. But sometimes we <em>need</em> our code to be asynchronous.</p>
<p>For example, whenever you update your user settings on a website, your browser will need to communicate those new settings to the server. The time it takes your HTTP request to physically travel across all the wiring of the internet is usually around 100 milliseconds. It would be a very poor experience if your webpage were to freeze while waiting for the network request to finish. You wouldn't even be able to move the mouse while waiting!</p>
<p>By making network requests <em>asynchronously</em>, we let the webpage execute other code while waiting for the HTTP response to come back. This keeps the user experience snappy and user-friendly.</p>
<p>As a general rule, we should only use async code when we need to for performance reasons. Synchronous code is simpler.</p>
<p><img src="https://i.imgur.com/03FFGu0.png" alt="Image" width="587" height="335" loading="lazy"></p>
<h3 id="heading-promises-in-javascript">Promises in JavaScript</h3>
<p>A Promise in JavaScript is very similar to making a promise in the real world. When we make a promise, we are making a commitment to something.</p>
<p>For example, <em>I promise to explain JavaScript promises to you</em>. My promise to you has 2 potential outcomes: it is either fulfilled, meaning I eventually explained promises to you, or it is rejected, meaning I failed to keep my promise and didn't explain promises.</p>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise Object</a> represents the eventual fulfillment or rejection of our promise and holds the resulting values. In the meantime, while we're waiting for the promise to be fulfilled, our code continues executing.</p>
<p>Promises are the most popular modern way to write asynchronous code in JavaScript.</p>
<h3 id="heading-how-to-declare-a-promise">How to Declare a Promise</h3>
<p>Here is an example of a promise that will resolve and return the string "resolved!" or reject and return the string "rejected!" after 1 second.</p>
<pre><code class="lang-plaintext">const promise = new Promise((resolve, reject) =&gt; {
  setTimeout(() =&gt; {
    if (getRandomBool()) {
      resolve("resolved!")
    } else {
      reject("rejected!")
    }
  }, 1000)
})

function getRandomBool(){
  return Math.random() &lt; .5
}
</code></pre>
<h3 id="heading-how-to-use-a-promise">How to Use a Promise</h3>
<p>Now that we've created a promise, how do we use it?</p>
<p>The <code>Promise</code> object has <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">.then</a> and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">.catch</a> that make it easy to work with. Think of <code>.then</code> as the <em>expected</em> follow-up to a promise, and <code>.catch</code> as the "something went wrong" follow-up.</p>
<p>If a promise <em>resolves</em>, its <code>.then</code> function will execute. If the promise rejects, its <code>.catch</code> method will execute.</p>
<p>Here's an example of using <code>.then</code> and <code>.catch</code> with the promise we made above:</p>
<pre><code class="lang-js">promise.then(<span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`The promise finally <span class="hljs-subst">${message}</span>`</span>)
}).catch(<span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`The promise finally <span class="hljs-subst">${message}</span>`</span>)
})

<span class="hljs-comment">// prints:</span>
<span class="hljs-comment">// The promise finally resolved!</span>
<span class="hljs-comment">// or</span>
<span class="hljs-comment">// the promise finally rejected!</span>
</code></pre>
<h3 id="heading-why-are-promises-useful">Why are Promises useful?</h3>
<p>Promises are the cleanest (but not the only) way to handle the common scenario where we need to make requests to a server, which is typically done via an HTTP request. In fact, the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">fetch()</a> function we were using earlier in the course returns a promise!</p>
<h3 id="heading-io-or-inputoutput">I/O, or "input/output"</h3>
<p>Almost every time you use a promise in JavaScript it will be to handle some form of I/O. I/O, or input/output, refers to when our code needs to interact with systems outside of the (relatively) simple world of local variables and functions.<br>Common examples of I/O include:</p>
<ul>
<li><p>HTTP requests</p>
</li>
<li><p>Reading files from the hard drive</p>
</li>
<li><p>Interacting with a Bluetooth device</p>
</li>
</ul>
<p>Promises help us perform I/O without forcing our entire program to freeze up while we wait for a response.</p>
<h3 id="heading-promises-and-the-await-keyword">Promises and the "await" keyword</h3>
<p>We have used the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await">await</a> keyword a few times in this course, so it's time we finally understand what's going on under the hood.</p>
<p>The <code>await</code> keyword is used to <em>wait</em> for a promise to resolve. Once it has been resolved, the <code>await</code> expression returns the value of the resolved <code>Promise</code>.</p>
<h3 id="heading-example-with-then-callback">Example with .then callback</h3>
<pre><code class="lang-js">promise.then(<span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Resolved with <span class="hljs-subst">${message}</span>`</span>)
}).
</code></pre>
<h3 id="heading-example-of-awaiting-a-promise">Example of awaiting a promise</h3>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> message = <span class="hljs-keyword">await</span> promise
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Resolved with <span class="hljs-subst">${message}</span>`</span>)
</code></pre>
<h3 id="heading-the-async-keyword">The async keyword</h3>
<p>While the <code>await</code> keyword can be used in place of <code>.then()</code> to <em>resolve</em> a promise, the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async</a> keyword can be used in place of <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise">new promise()</a> to <em>create</em> a new promise.</p>
<p>When a function is prefixed with the <code>async</code> keyword, it will <em>automatically</em> return a promise. That promise resolves with the value that your code returns from the function. You can think of <code>async</code> as "wrapping" your function within a promise.</p>
<p>These are equivalent:</p>
<h3 id="heading-new-promise">New Promise()</h3>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPromiseForUserData</span>(<span class="hljs-params"></span>)</span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> {
    fetchDataFromServerAsync().then(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">user</span>)</span>{
      resolve(user)
    })
  })
}

<span class="hljs-keyword">const</span> promise = getPromiseForUserData()
</code></pre>
<h3 id="heading-async">Async</h3>
<pre><code class="lang-js"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPromiseForUserData</span>(<span class="hljs-params"></span>)</span>{
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> fetchDataFromServer()
  <span class="hljs-keyword">return</span> user
}

<span class="hljs-keyword">const</span> promise = getPromiseForUserData()
</code></pre>
<h3 id="heading-then-vs-await">.then() vs await</h3>
<p>In the early days of web browsers, promises and the <code>await</code> keyword didn't exist, so the only way to do something asynchronously was to use callbacks.</p>
<p>A "callback function" is a function that you hand to another function. That function then calls your callback later on. The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/setTimeout">setTimeout</a> function we've used in the past is a good example.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">callbackFunction</span>(<span class="hljs-params"></span>)</span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"calling back now!"</span>)
}
<span class="hljs-keyword">const</span> milliseconds = <span class="hljs-number">1000</span>
<span class="hljs-built_in">setTimeout</span>(callbackFunction, milliseconds)
</code></pre>
<p>While even the <code>.then()</code> syntax is generally easier to use than callbacks without the <code>Promise</code> API, the <code>await</code> syntax makes them even easier to use. You should use <code>async</code> and <code>await</code> over <code>.then</code> and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise">new Promise()</a> as a general rule.</p>
<p>To demonstrate, which of these is easier to understand?</p>
<pre><code class="lang-js">fetchUser.then(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">user</span>)</span>{
  <span class="hljs-keyword">return</span> fetchLocationForUser(user)
}).then(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">location</span>)</span>{
  <span class="hljs-keyword">return</span> fetchServerForLocation(location)
}).then(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">server</span>)</span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`The server is <span class="hljs-subst">${server}</span>`</span>)
});
</code></pre>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> fetchUser()
<span class="hljs-keyword">const</span> location = <span class="hljs-keyword">await</span> fetchLocationForUser(user)
<span class="hljs-keyword">const</span> server = <span class="hljs-keyword">await</span> fetchServerForLocation(location)
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`The server is <span class="hljs-subst">${server}</span>`</span>)
</code></pre>
<p>They both do the same thing, but the second example is so much easier to understand! The <code>async</code> and <code>await</code> keywords weren't released until <em>after</em> the <code>.then</code> API, which is why there is still a lot of legacy <code>.then()</code> code out there.</p>
<h2 id="heading-error-handling">Error Handling</h2>
<p>When something goes wrong while a program is running, JavaScript uses the <code>try/catch</code> paradigm for handling those errors. Try/catch is fairly common, and <a target="_blank" href="https://boot.dev/learn/learn-python">Python</a> uses a similar mechanism.</p>
<h3 id="heading-first-an-error-is-thrown">First, an error is thrown</h3>
<p>For example, let's say we try to access a property on an undefined variable. JavaScript will automatically "throw" an error.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> speed = car.speed
<span class="hljs-comment">// The code crashes with the following error:</span>
<span class="hljs-comment">// "ReferenceError: car is not defined"</span>
</code></pre>
<h3 id="heading-trying-and-catching-errors">Trying and catching errors</h3>
<p>By wrapping that code in a try/catch block, we can handle the case where <code>car</code> is not yet defined.</p>
<pre><code class="lang-js"><span class="hljs-keyword">try</span> {
  <span class="hljs-keyword">const</span> speed = car.speed
} <span class="hljs-keyword">catch</span> (err) {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`An error was thrown: <span class="hljs-subst">${err}</span>`</span>)
  <span class="hljs-comment">// the code cleanly logs:</span>
  <span class="hljs-comment">// "An error was thrown: ReferenceError: car is not defined"</span>
}
</code></pre>
<h3 id="heading-bugs-vs-errors">Bugs vs Errors</h3>
<p>Error handling via try/catch is not the same as debugging. Likewise, errors are not the same as bugs.</p>
<ul>
<li><p>Good code with no bugs can still produce errors that are gracefully handled</p>
</li>
<li><p>Bugs are, by definition, bits of code that aren't working as intended</p>
</li>
</ul>
<h3 id="heading-what-is-debugging">What is Debugging?</h3>
<p>"Debugging" a program is the process of going through your code to find where it is not behaving as expected. Debugging is a manual process performed by the developer.</p>
<p>Examples of debugging:</p>
<ul>
<li><p>Adding a missing parameter to a function call</p>
</li>
<li><p>Updating a broken URL that an HTTP call was trying to reach</p>
</li>
<li><p>Fixing a date-picker component in an app that wasn't displaying properly</p>
</li>
</ul>
<h3 id="heading-what-is-error-handling">What is Error Handling?</h3>
<p>"Error handling" is code that can handle <em>expected</em> edge cases in your program. Error handling is an automated process that we design into our production code to protect it from things like weak internet connections, bad user input, or bugs in other people's code that we have to interface with.</p>
<p>Examples of error handling:</p>
<ul>
<li><p>Using a try/catch block to detect an issue with user input</p>
</li>
<li><p>Using a try/catch block to gracefully fail when no internet connection is available</p>
</li>
</ul>
<h3 id="heading-in-short-dont-use-trycatch-to-try-to-handle-bugs">In short, don't use try/catch to try to handle bugs</h3>
<p>If your code has a <a target="_blank" href="https://en.wikipedia.org/wiki/Software_bug">bug</a>, try/catch won't help you. You need to just go find the bug and fix it.</p>
<p>If something out of your control can produce issues in your code, you should use try/catch or other error-handling logic to deal with it.</p>
<p>For example, there could be a prompt in a game for users to type in a new character name, but we don't want them to use punctuation. Validating their input and displaying an error message if something is wrong with it would be a form of "error handling".</p>
<h3 id="heading-asyncawait-makes-error-handling-easier">async/await makes error handling easier</h3>
<p><code>try</code> and <code>catch</code> are the standard way to handle errors in JavaScript, the trouble is, the original Promise API with <code>.then</code> didn't allow us to make use of <code>try</code> and <code>catch</code> blocks.</p>
<p>Luckily, the <code>async</code> and <code>await</code> keywords <em>do</em> allow it - yet another reason to prefer the newer syntax.</p>
<h3 id="heading-catch-callback-on-promises">.catch() callback on promises</h3>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">.catch()</a> method works similarly to the .then() method, but it fires when a promise is <em>rejected</em> instead of resolved.</p>
<h3 id="heading-example-with-then-and-catch-callbacks">Example with .then and .catch callbacks</h3>
<pre><code class="lang-js">fetchUser().then(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">user</span>)</span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`user fetched: <span class="hljs-subst">${user}</span>`</span>)
}).catch(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">err</span>)</span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`an error was thrown: <span class="hljs-subst">${err}</span>`</span>)
});
</code></pre>
<h3 id="heading-example-of-awaiting-a-promise-1">Example of awaiting a promise</h3>
<pre><code class="lang-js"><span class="hljs-keyword">try</span> {
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> fetchUser()
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`user fetched: <span class="hljs-subst">${user}</span>`</span>)
} <span class="hljs-keyword">catch</span> (err) {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`an error was thrown: <span class="hljs-subst">${err}</span>`</span>)
}
</code></pre>
<p>As you can see, the <code>async/await</code> version looks just like normal <code>try/catch</code> JavaScript.</p>
<h2 id="heading-http-headers">HTTP Headers</h2>
<p>An <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/HTTP_header">HTTP header</a> allows clients and servers to pass <em>additional</em> information with each request or response. Headers are just case-insensitive <a target="_blank" href="https://en.wikipedia.org/wiki/Name%E2%80%93value_pair">key-value pairs</a> that pass additional <a target="_blank" href="https://en.wikipedia.org/wiki/Metadata">metadata</a> about the request or response.</p>
<p>HTTP requests from a web browser carry with them many headers, including but not limited to:</p>
<ul>
<li><p>The type of client (for example Google Chrome)</p>
</li>
<li><p>The Operating system (for example Windows)</p>
</li>
<li><p>The preferred language (for example US English)</p>
</li>
</ul>
<p>As developers, we can also define custom headers in each request.</p>
<h3 id="heading-headers-api">Headers API</h3>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Headers">Headers</a> API allows us to perform various actions on our request and response headers such as retrieving, setting, and removing them. We can access the headers object through the <code>Request.headers</code> and <code>Response.headers</code> properties.</p>
<h3 id="heading-how-to-use-the-browsers-developer-tools">How to Use the Browser's Developer Tools</h3>
<p>Modern web browsers offer developers a powerful set of <em>developer tools</em>. The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">Developer Tools</a> are a front-end web developer's best friend. For example, using the dev tools you can:</p>
<ul>
<li><p>View the web page's JavaScript console output</p>
</li>
<li><p>Inspect the page's HTML, CSS, and JavaScript code</p>
</li>
<li><p>View network requests and responses, along with their headers</p>
</li>
</ul>
<p>The method for accessing dev tools varies from browser to browser. If you're on Chrome, you can just right-click anywhere within a web page and click the "inspect" option. Follow this link for more info on <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools#:~:text=How%20do%20you%20pull%20it%20up%3F%20Three%20ways%3A">how to access dev tools</a>.</p>
<h3 id="heading-the-network-tab">The network tab</h3>
<p>While all of the tabs within the dev tools are very useful, we will be focusing specifically on the <em>Network tab</em> in this chapter so we can play with HTTP headers.</p>
<p>The Network tab monitors your browser's network activity and records all of the requests and responses the browser is making, including how long each of those requests and responses takes to fully process.</p>
<p>If you navigate to the Network tab and don't see any requests appear, try refreshing the page.</p>
<p><img src="https://i.imgur.com/STKdceG.png" alt="Image" width="580" height="372" loading="lazy"></p>
<h3 id="heading-why-are-headers-useful">Why are headers useful?</h3>
<p>Headers are useful for several reasons, from design to security. But most often headers are used as <a target="_blank" href="https://en.wikipedia.org/wiki/Metadata">metadata</a> or data <em>about</em> the request.</p>
<p>So, for example, let's say we wanted to ask for a player's level from a game's server. We need to send that player's ID to the server so it knows which player to send back the information for. That ID <em>is my request</em>, it's not information <em>about my request</em>.</p>
<p>A good example of a use case for headers is <a target="_blank" href="https://auth0.com/intro-to-iam/what-is-authentication/">authentication</a>. Often times a user's credentials are included in request headers. Credentials don't have much to do with the request <em>itself</em>, but simply authorize the requester to be allowed to make the request in question.</p>
<h2 id="heading-what-is-json">What is JSON?</h2>
<p>JavaScript Object Notation, or <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON">JSON</a>, is a standard for representing <em>structured</em> data based on JavaScript's object syntax.</p>
<p>JSON is commonly used to transmit data in web apps using HTTP. The HTTP <code>fetch()</code> requests we have been using in this course have been returning data as JSON data.</p>
<h3 id="heading-json-syntax">JSON Syntax</h3>
<p>Because we already understand what JavaScript objects look like, understanding JSON is easy. JSON is just a stringified JavaScript object. The following is valid JSON data:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"movies"</span>: [
        {
            <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
            <span class="hljs-attr">"genre"</span>: <span class="hljs-string">"Action"</span>,
            <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Iron Man"</span>,
            <span class="hljs-attr">"director"</span>: <span class="hljs-string">"Jon Favreau"</span>
        },
        {
            <span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>,
            <span class="hljs-attr">"genre"</span>: <span class="hljs-string">"Action"</span>,
            <span class="hljs-attr">"title"</span>: <span class="hljs-string">"The Avengers"</span>,
            <span class="hljs-attr">"director"</span>: <span class="hljs-string">"Joss Whedon"</span>
        }
    ]
}
</code></pre>
<h3 id="heading-how-to-parse-http-responses-as-json">How to Parse HTTP Responses as JSON</h3>
<p>JavaScript provides us with some easy tools to help us work with JSON. After making an HTTP request with the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">fetch() API</a>, we get a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Response">Response object</a>. That response object offers us some methods that help us interact with the response.</p>
<p>One such method is the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Response/json">.json()</a> method. The <code>.json()</code> method takes the response stream returned by a fetch request and returns a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a> that resolves into a JavaScript object parsed from the JSON body of the HTTP response.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> resp = <span class="hljs-keyword">await</span> fetch(...)
<span class="hljs-keyword">const</span> javascriptObjectResponse = <span class="hljs-keyword">await</span> resp.json()
</code></pre>
<p>It's important to note that the result of the <code>.json()</code> method is <em>NOT</em> JSON. It is the result of taking JSON data from the HTTP response body and parsing that input into a JavaScript Object.</p>
<h3 id="heading-json-review">JSON Review</h3>
<p>JSON is a <em>stringified representation</em> of a JavaScript object, which makes it perfect for saving to a file or sending in an HTTP request.</p>
<p>Remember, an actual JavaScript object is something that exists only within your program's variables. If we want to send an object outside our program, for example, across the internet in an HTTP request, we need to convert it to JSON first.</p>
<h3 id="heading-its-not-just-used-in-javascript">It's not just used in JavaScript</h3>
<p>Just because JSON is called <em>JavaScript</em> Object Notation doesn't mean it's only used by JavaScript! JSON is a common standard that is recognized and supported by every major programming language.</p>
<p>For example, even though Boot.dev's backend API is written in <a target="_blank" href="https://boot.dev/learn/learn-golang">Go</a>, we still use <a target="_blank" href="https://blog.boot.dev/golang/json-golang/">JSON</a> as the communication format between the front-end and backend.</p>
<p>By the way, this course has been about interacting with back-end servers from a front-end perspective. But if you're curious about how you can become a back-end engineer, <a target="_blank" href="https://blog.boot.dev/backend/become-backend-developer/">check out this guide</a> I've put together. For reference, it takes most people <a target="_blank" href="https://blog.boot.dev/backend/how-long-to-become-backend-dev/">between 6-18 months</a> to learn enough to get their first <a target="_blank" href="https://blog.boot.dev/backend/backend-job-description/">back-end job</a>.</p>
<h3 id="heading-common-json-use-cases">Common JSON use-cases</h3>
<ul>
<li><p>In HTTP request and response bodies</p>
</li>
<li><p>As formats for text files. <code>.json</code> files are often used as configuration files.</p>
</li>
<li><p>In NoSQL databases like MongoDB, ElasticSearch, and Firestore</p>
</li>
</ul>
<h3 id="heading-how-to-pronounce-json">How to Pronounce JSON</h3>
<p>I pronounce it "Jay-sawn", but I've also heard people pronounce it "Jason", like the name.</p>
<h3 id="heading-how-to-send-json">How to Send JSON</h3>
<p>JSON isn't just something we get from the server, we can also <em>send</em> JSON data.<br>In JavaScript, two of the main methods we have access to are <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse">JSON.parse()</a>, and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify">JSON.stringify()</a>.</p>
<h4 id="heading-jsonstringify"><code>JSON.stringify()</code></h4>
<p><code>JSON.stringify()</code> is particularly useful for <em>sending</em> JSON.</p>
<p>As you may expect, the JSON <code>stringify()</code> method does the opposite of parse. It takes a JavaScript object or value as input and converts it into a string. This is useful when we need to serialize the objects into strings to send them to our server or store them in a database.</p>
<p>Here's a snippet of code that sends a JSON payload to a remote server:</p>
<pre><code class="lang-plaintext">async function sendPayload(data, headers) {
  const response = await fetch(url, {
    method: 'POST',
    mode: 'cors',
    headers: headers,
    body: JSON.stringify(data)
  })
  return response.json()
}
</code></pre>
<h3 id="heading-how-to-parse-json">How to Parse JSON</h3>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse">JSON.parse()</a> method takes a JSON string as input and constructs the JavaScript value/object described by the string. This allows us to work with the JSON as a normal JavaScript object.</p>
<p>Seeing as JSON objects have a tree-like structure, it can be helpful to know how to <a target="_blank" href="https://blog.boot.dev/javascript/how-to-recursively-traverse-objects/">traverse them recursively</a> if needs be.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> json = <span class="hljs-string">'{"title": "Avengers Endgame", "Rating":4.7, "inTheaters":false}'</span>;
<span class="hljs-keyword">const</span> obj = <span class="hljs-built_in">JSON</span>.parse(json)

<span class="hljs-built_in">console</span>.log(obj.title)
<span class="hljs-comment">// Avengers Endgame</span>
</code></pre>
<h3 id="heading-xml">XML</h3>
<p>We can't talk about JSON without mentioning <a target="_blank" href="https://en.wikipedia.org/wiki/XML#:~:text=Extensible%20Markup%20Language%20\(XML\)%20is,%2Dreadable%20and%20machine%2Dreadable.">XML</a>. Extensible Markup Language, or <code>XML</code> is a text-based format for representing structured information, just like JSON - it just looks a bit different.</p>
<p>XML is a markup language like <a target="_blank" href="https://en.wikipedia.org/wiki/HTML">HTML</a>, but it's more generalized in that it does <em>not</em> use predefined tags. Just like how in a JSON object keys can be called anything, XML tags can also have any name.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">root</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">id</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">id</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">genre</span>&gt;</span>Action<span class="hljs-tag">&lt;/<span class="hljs-name">genre</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Iron Man<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">director</span>&gt;</span>Jon Favreau<span class="hljs-tag">&lt;/<span class="hljs-name">director</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">root</span>&gt;</span>
</code></pre>
<p>The same data in JSON form:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"id"</span>: <span class="hljs-string">"1"</span>,
  <span class="hljs-attr">"genre"</span>: <span class="hljs-string">"Action"</span>,
  <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Iron Man"</span>,
  <span class="hljs-attr">"director"</span>: <span class="hljs-string">"Jon Favreau"</span>
}
</code></pre>
<h3 id="heading-why-use-xml">Why use XML?</h3>
<p>XML and JSON both accomplish similar tasks, so which should you use?</p>
<p>XML used to be used for the same things that today JSON is used for. Configuration files, HTTP bodies, and other data-transfer use cases can work just fine using JSON or XML. Here's my advice: generally speaking, if JSON works, you should favor it over XML these days. JSON is lighter-weight, easier to read, and has better support in most modern programming languages.</p>
<p>There are some cases where XML might still be the better, or maybe even the necessary choice, but those cases will be rare.</p>
<h2 id="heading-http-methods">HTTP Methods</h2>
<p>HTTP defines a set of <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods">methods</a> that we use every time we make a request. We have used some of these methods in previous exercises, but it's time we dive into them and understand the differences and use cases behind the different methods.</p>
<h3 id="heading-the-get-method">The GET method</h3>
<p>The <a target="_blank" href="https://www.freecodecamp.org/news/javascript-get-request-tutorial/">GET method</a> is used to "get" a representation of a specified resource. You are not taking the data away from the server, but rather getting a representation, or copy, of the resource in its current state.</p>
<p>A get request is considered a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Safe/HTTP">safe</a> method to call multiple times because it doesn't alter the state of the server.</p>
<h3 id="heading-how-to-make-a-get-request-using-the-fetch-api">How to Make a GET Request using the Fetch API</h3>
<p>The fetch() method accepts an optional <code>init</code> object parameter as its second argument that we can use to define things like:</p>
<ul>
<li><p><code>method</code>: The HTTP method of the request, like <code>GET</code>.</p>
</li>
<li><p><code>headers</code>: The headers to send.</p>
</li>
<li><p><code>mode</code>: Used for security, we'll talk about this in future courses</p>
</li>
<li><p><code>body</code>: The body of the request. Often encoded as JSON.</p>
</li>
</ul>
<p>Example <code>GET</code> request using fetch:</p>
<pre><code class="lang-js"><span class="hljs-keyword">await</span> fetch(url, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span>,
  <span class="hljs-attr">mode</span>: <span class="hljs-string">'cors'</span>,
  <span class="hljs-attr">headers</span>: {
    <span class="hljs-string">'sec-ch-ua-platform'</span>: <span class="hljs-string">'macOS'</span>
  }
})
</code></pre>
<h3 id="heading-why-do-we-use-http-methods">Why do we use HTTP methods?</h3>
<p>As we touched on before, the primary purpose of HTTP methods is to indicate to the server what we want to do with the resource we're trying to interact with.</p>
<p>At the end of the day, an HTTP method is just a string, like <code>GET</code>, <code>POST</code>, <code>PUT</code>, or <code>DELETE</code>. But by <em>convention</em>, backend developers almost always write their server code so that the methods correspond with different "CRUD" actions.</p>
<p>The "CRUD" actions are:</p>
<ul>
<li><p>Create</p>
</li>
<li><p>Read</p>
</li>
<li><p>Update</p>
</li>
<li><p>Delete</p>
</li>
</ul>
<p>The bulk of the logic in most web applications is "CRUD" logic. The web interface allows users to create, read, update and delete various resources.</p>
<p>Think of a social media site - users are basically creating, reading, updating and deleting their social posts. They are also creating, reading, updating and deleting their user accounts. It's CRUD all the way down!</p>
<p>As it happens, the 4 most common HTTP methods map nicely to the CRUD actions:</p>
<ul>
<li><p><code>POST</code> = create</p>
</li>
<li><p><code>GET</code> = read</p>
</li>
<li><p><code>PUT</code> = update</p>
</li>
<li><p><code>DELETE</code> = delete</p>
</li>
</ul>
<h3 id="heading-post-requests">POST Requests</h3>
<p>An <a target="_blank" href="https://www.freecodecamp.org/news/javascript-post-request-how-to-send-an-http-post-request-in-js/">HTTP POST request</a> sends data to a server, typically to create a new resource. The <code>body</code> of the request is the <em>payload</em> that is being sent to the server with the request. Its type is indicated by the <code>Content-Type</code> header.</p>
<h3 id="heading-how-to-add-a-body">How to Add a <code>body</code></h3>
<p>The <code>body</code> of the request is the <em>payload</em> that is being sent to the server with the request. Its type is indicated by the <code>Content-Type</code> header - for us, that's going to be JSON.</p>
<p><code>POST</code> requests are generally <em>not</em> safe methods to call multiple times, because it alters the state of the server. You wouldn't want to accidentally create 2 accounts for the same user, for example.</p>
<pre><code class="lang-js"><span class="hljs-keyword">await</span> fetch(url, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
  <span class="hljs-attr">mode</span>: <span class="hljs-string">'cors'</span>,
  <span class="hljs-attr">headers</span>: {
    <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
  },
  <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(data)
})
</code></pre>
<h3 id="heading-http-status-codes">HTTP Status Codes</h3>
<p>Now that we understand how to write HTTP requests from scratch, we need to learn how to ensure that the server is doing what we want.</p>
<p>Earlier in the course, we learned about how to access the browser's <em>developer tools</em> and use those tools to inspect HTTP requests. We can use that same process to check on the requests we are making and verify what they are doing so we can address potential problems.</p>
<p>When looking at requests, we can check on the <code>Status Code</code> of the request to get some information if the request was successful or not.</p>
<ul>
<li><p><code>100-199</code>: Informational responses. These are very rare.</p>
</li>
<li><p><code>200-299</code>: Successful responses. Hopefully, most responses are 200's!</p>
</li>
<li><p><code>300-399</code>: Redirection messages. These are typically invisible because the browser or HTTP client will automatically do the redirect.</p>
</li>
<li><p><code>400-499</code>: Client errors. You'll see these often, especially when trying to debug a client application</p>
</li>
<li><p><code>500-599</code>: Server errors. You'll see these sometimes, usually only if there is a bug on the server.</p>
</li>
</ul>
<p>Here are some of the most common status codes, but you can see a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status">full list here</a> if you're interested.</p>
<ul>
<li><p><code>200</code> - OK. This is by far the most common code, it just means that everything worked as expected.</p>
</li>
<li><p><code>201</code> - Created. This means that a resource was created successfully. Typically in response to a <code>POST</code> request.</p>
</li>
<li><p><code>301</code> - Moved permanently. This means the resource was moved to a new place, and the response will include where that new place is. Websites often use <code>301</code> redirects when they change their domain name, for example.</p>
</li>
<li><p><code>400</code> - Bad request. A general error indicating the client made a mistake in their request.</p>
</li>
<li><p><code>403</code> - Unauthorized. This means the client doesn't have the correct permissions. Maybe they didn't include a required authorization header, for example.</p>
</li>
<li><p><code>404</code> - Not found. You'll see this on websites quite often. It just means the resource doesn't exist.</p>
</li>
<li><p><code>500</code> - Internal server error. This means something went wrong on the server, likely a bug on their end.</p>
</li>
</ul>
<h3 id="heading-you-dont-need-to-memorize-them">You don't need to memorize them</h3>
<p>You need to know the basics, like "2XX is good", "4XX is a client error", and "5XX is a server error". That said, you don't need to memorize all the codes, they're easy to look up.</p>
<p><img src="https://i.imgur.com/FJl2z9O.jpg" alt="Image" width="549" height="454" loading="lazy"></p>
<p>Let's check some status codes!</p>
<p>The <code>.status</code> property on a Response object will give you the code. Here's an example:</p>
<pre><code class="lang-js"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStatusCode</span>(<span class="hljs-params">url, headers</span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(url, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span>,
    <span class="hljs-attr">mode</span>: <span class="hljs-string">'cors'</span>,
    <span class="hljs-attr">headers</span>: headers
  })
  <span class="hljs-keyword">return</span> response.status
}
</code></pre>
<h3 id="heading-put-method">PUT Method</h3>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT">HTTP PUT method</a> creates a new resource or replaces a representation of the target resource with the contents of the request's <code>body</code>. In short, it updates a resource's properties.</p>
<pre><code class="lang-js"><span class="hljs-keyword">await</span> fetch(url, {
   <span class="hljs-attr">method</span>: <span class="hljs-string">'PUT'</span>,
   <span class="hljs-attr">mode</span>: <span class="hljs-string">'cors'</span>,
   <span class="hljs-attr">headers</span>: {
   <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>
   },
   <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(data)
})
</code></pre>
<h3 id="heading-post-vs-put">POST vs PUT</h3>
<p>You may be thinking <code>PUT</code> is similar to <code>POST</code> or <code>PATCH</code>, and frankly, you'd be right. The main difference is that PUT is meant to be <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Idempotent">idempotent</a>, meaning multiple identical PUT requests should have the same effect on the server.</p>
<p>In contrast, several identical <code>POST</code> requests would have additional side effects, such as creating multiple copies of the resource.</p>
<h3 id="heading-http-patch-vs-put">HTTP Patch vs PUT</h3>
<p>You may encounter <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH">PATCH</a> methods from time to time. While it is not nearly as common as the other methods, like <code>PUT</code>, it's important to know about it and what it does. The <code>PATCH</code> method is intended to <em>partially</em> modify a resource.</p>
<p>Long story short, <code>PATCH</code> isn't nearly as popular as <code>PUT</code>, and many servers, even if they allow partial updates, will still just use the <code>PUT</code> method for that.</p>
<h3 id="heading-http-delete">HTTP Delete</h3>
<p>The <code>DELETE</code> method does exactly as you would expect: it's conventionally used to delete a specified resource.</p>
<pre><code class="lang-js"><span class="hljs-comment">// This deletes the location with ID: 52fdfc07-2182-454f-963f-5f0f9a621d72</span>
<span class="hljs-keyword">const</span> url = <span class="hljs-string">'https://example-api.com/locations/52fdfc07-2182-454f-963f-5f0f9a621d72'</span>

<span class="hljs-keyword">await</span> fetch(url, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">'DELETE'</span>,
  <span class="hljs-attr">mode</span>: <span class="hljs-string">'cors'</span>
})
</code></pre>
<h2 id="heading-url-paths-and-parameters">URL Paths and Parameters</h2>
<p>The URL Path comes right after the domain (or port if one is provided) in a URL string.</p>
<p>In this URL, the path is <code>/root/next</code>: <code>http://testdomain.com/root/next</code>.</p>
<h3 id="heading-what-paths-meant-in-the-early-internet">What paths meant in the early internet</h3>
<p>In the early days of the internet, and sometimes still today, many web servers simply served raw files from the server's file system.</p>
<p>For example, if I wanted you to be able to access some text documents, I could start a web server in my <code>documents</code> directory. If you made a request to my server, you would be able to access different documents by using the path that matched my local file structure.</p>
<p>If I had a file in my local <code>/documents/hello.txt</code>, you could access it by making a <code>GET</code> request to <code>http://example.com/documents/hello.txt</code>.</p>
<h3 id="heading-how-paths-are-used-today">How paths are used today</h3>
<p>Most modern web servers don't use that simple mapping of <code>URL path</code> -&gt; <code>file path</code>. Technically, a URL path is just a string that the web server can do what it wants with, and modern websites take advantage of that flexibility.</p>
<p>Some common examples of what paths are used for include:</p>
<ul>
<li><p>The hierarchy of pages on a website, whether or not that reflects a server's file structure</p>
</li>
<li><p>Parameters being passed into an HTTP request, like an ID of a resource</p>
</li>
<li><p>The version of the API</p>
</li>
<li><p>The type of resource being requested</p>
</li>
</ul>
<h3 id="heading-restful-apis">RESTful APIs</h3>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/REST">Representational State Transfer, or REST</a>, is a popular convention that HTTP servers follow. Not all HTTP APIs are "REST APIs", or "RESTful", but it is <em>very</em> common.</p>
<p>RESTful servers follow a loose set of rules that makes it easy to build reliable and predictable web APIs. REST is more or less a set of conventions about how HTTP <em>should</em> be used.</p>
<h3 id="heading-separate-and-agnostic">Separate and agnostic</h3>
<p>The big idea behind REST is that resources are transferred via well-recognized, language-agnostic client/server interactions.</p>
<p>A RESTful style means the implementation of the client and server can be done independently of one another, as long as some simple standards, like the names of the available resources, have been established.</p>
<h3 id="heading-stateless">Stateless</h3>
<p>A RESTful architecture is stateless. This means that the server does not need to know what state the client is in, nor does the client need to know what state the server is in.</p>
<p>Statelessness in REST is enforced by interacting with resources instead of commands. Keep in mind, this doesn't mean the applications are stateless - on the contrary, what would "updating a resource" even mean if the server wasn't keeping track of its state?</p>
<h3 id="heading-paths-in-rest">Paths in REST</h3>
<p>In a RESTful API, the last section of the <code>path</code> of a URL should specify which resource is being accessed. Then, as we talked about in the "methods" section, depending on whether the request is a <code>GET</code>, <code>POST</code>, <code>PUT</code> or <code>DELETE</code>, the resource is read, created, updated, or deleted.</p>
<p>For example, in the <a target="_blank" href="https://pokeapi.co/">PokeAPI</a>:</p>
<ul>
<li><p><a target="_blank" href="https://pokeapi.co/api/v2/pokemon/"><code>https://pokeapi.co/api/v2/pokemon/</code></a></p>
</li>
<li><p><a target="_blank" href="https://pokeapi.co/api/v2/pokemon/"><code>https://pokeapi.co/api/v2/location/</code></a></p>
</li>
</ul>
<p>The first part of the path specifies that we're interacting with an API rather than a website. The next part specifies the version, in this case, version 2, or <code>v2</code>.</p>
<p>Finally, the last part denotes which resource is being accessed, be it a <code>location</code> or <code>pokemon</code>.</p>
<h3 id="heading-url-query-parameters">URL Query Parameters</h3>
<p>A URL's query parameters appear next in the URL structure but are <em>not</em> always present - they're optional. For example:</p>
<p><a target="_blank" href="https://www.google.com/search?q=boot.dev">https://www.google.com/search?q=boot.dev</a></p>
<p><code>q=boot.dev</code> is a query parameter. Like headers, query parameters are <code>key / value</code> pairs. In this case, <code>q</code> is the key and <code>boot.dev</code> is the value.</p>
<h3 id="heading-the-documentation-of-an-http-server">The Documentation of an HTTP Server</h3>
<p>You may be wondering:</p>
<blockquote>
<p>How the heck am I supposed to memorize how all these different servers work???</p>
</blockquote>
<p>The good news is that <em>you don't need to</em>. When you work with a backend server, it's the responsibility of that server's developers to provide you with instructions, or <em>documentation</em> that explains how to interact with it.</p>
<p>For example, the documentation should tell you:</p>
<ul>
<li><p>The domain of the server</p>
</li>
<li><p>The resources you can interact with (HTTP paths)</p>
</li>
<li><p>The supported query parameters</p>
</li>
<li><p>The supported HTTP methods</p>
</li>
<li><p>Anything else you'll need to know to work with the server</p>
</li>
</ul>
<p><img src="https://i.imgur.com/GIlWhYF.jpg" alt="Image" width="500" height="553" loading="lazy"></p>
<p>The server has control</p>
<p>As we mentioned earlier, the server has complete control over how the path in a URL is interpreted and used in a request. The same goes for query parameters.</p>
<p>Not all servers support query parameters for every type of request, it just depends, so you'll need to consult the docs.</p>
<h3 id="heading-multiple-query-parameters">Multiple Query Parameters</h3>
<p>We mentioned that query parameters are <code>key/value</code> pairs - that means we can have multiple pairs.</p>
<p><code>http://example.com?firstName=lane&amp;lastName=wagner</code></p>
<p>In the example above:</p>
<ul>
<li><p><code>firstName</code> = <code>lane</code></p>
</li>
<li><p><code>lastName</code> = <code>wagner</code></p>
</li>
</ul>
<p>The <code>?</code> separates the query parameters from the rest of the URL. The <code>&amp;</code> is then used to separate <em>every pair</em> of query parameters after that.</p>
<p>For example, make this request to limit the number of Pokémon returned from the PokeAPI to <code>2</code>:</p>
<pre><code class="lang-plaintext">https://pokeapi.co/api/v2/location/?limit=2
</code></pre>
<h2 id="heading-what-is-https">What is HTTPs?</h2>
<p>Hypertext Transfer Protocol <em>Secure</em> or <a target="_blank" href="https://www.freecodecamp.org/news/what-is-https-http-vs-https-meaning-and-how-it-works/">HTTPS</a> is an extension of the HTTP protocol. HTTPS secures the data transfer between client and server by <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Encryption">encrypting</a> all of the communication.</p>
<p>HTTPS allows a client to safely share sensitive information with the server through an HTTP request, such as credit card information, passwords, or bank account numbers.</p>
<p>HTTPS requires that the client use <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/SSL">SSL</a> or <a target="_blank" href="https://www.freecodecamp.org/news/what-is-tls-transport-layer-security-encryption-explained-in-plain-english/">TLS</a> to protect requests and traffic by encrypting the information in the request. HTTPS is just HTTP with extra security.</p>
<p><img src="https://i.imgur.com/iOkQUdG.png" alt="Image" width="517" height="487" loading="lazy"></p>
<p><em>HTTP vs HTTPS</em></p>
<h3 id="heading-https-keeps-your-messages-private-but-not-your-identity">HTTPS keeps your messages private, but not your identity</h3>
<p>We won't cover <em>how</em> encryption works in this course, but we will in later courses. For now, it's important to note that while HTTPS encrypts <em>what you are saying</em>, it doesn't necessarily protect <em>who you are</em>. Tools like <a target="_blank" href="https://nordvpn.com/what-is-a-vpn/">VPNs</a> are needed for remaining anonymous online.</p>
<h3 id="heading-https-ensures-that-youre-talking-to-the-right-person-or-server">HTTPS ensures that you're talking to the right person (or server)</h3>
<p>In addition to encrypting the information within a request, HTTPS uses <a target="_blank" href="https://en.wikipedia.org/wiki/Digital_signature">digital signatures</a> to prove that you're communicating with the server that you think you are.</p>
<p>If a hacker were to intercept an HTTPS request by tapping into a network cable, they wouldn't be able to successfully pretend they are your bank's web server.</p>
<p>Assuming that a server supports HTTPs, you use it by simply changing the protocol on your request URL: <code>https://boot.dev</code></p>
<h3 id="heading-want-to-put-what-youve-learned-into-practice-with-a-project">Want to put what you've learned into practice with a project?</h3>
<p>Check out this <a target="_blank" href="https://boot.dev/build/link-analyzer">project guide where you'll build a web crawler in JavaScript</a> from scratch. It will have you using the Fetch API and parsing JSON data like a pro! You don't need to build the project, but it's a great way to practice what you're learned.</p>
<h2 id="heading-congratulations-on-making-it-to-the-end">Congratulations on making it to the end!</h2>
<p>If you're interested in doing the interactive coding assignments and quizzes for this course you can check out the <a target="_blank" href="https://boot.dev/learn/learn-object-oriented-programming">Learn HTTP course</a> over on <a target="_blank" href="https://boot.dev/">Boot.dev</a>.</p>
<p>This course is a part of my <a target="_blank" href="https://boot.dev/tracks/backend">full back-end developer career path</a>, made up of other courses and projects if you're interested in checking those out.</p>
<p>If you want to see the other content I'm creating related to web development, check out some of my links below:</p>
<ul>
<li><p><a target="_blank" href="https://twitter.com/wagslane">Lane on Twitter</a></p>
</li>
<li><p><a target="_blank" href="https://youtube.com/@bootdotdev">Lane on YouTube</a></p>
</li>
<li><p><a target="_blank" href="https://wagslane.dev">Lane's Personal Site</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Wireshark – Computer Networking Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ In this post, you will learn about the single most important and useful tool in Computer Networks – Wireshark. This post relies on basic knowledge of computer networks. Be sure to check my previous post about the five layers model if you need a refre... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-wireshark-computer-networking/</link>
                <guid isPermaLink="false">66c17c3dea5637f064224a0a</guid>
                
                    <category>
                        <![CDATA[ computer network ]]>
                    </category>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ information security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ #infosec ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Omer Rosenbaum ]]>
                </dc:creator>
                <pubDate>Mon, 23 Jan 2023 23:35:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/01/Computer-Networks-Ethernet--3-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this post, you will learn about the single most important and useful tool in Computer Networks – Wireshark.</p>
<p>This post relies on basic knowledge of computer networks. Be sure to check my <a target="_blank" href="https://www.freecodecamp.org/news/the-five-layers-model-explained/">previous post about the five layers model</a> if you need a refresher.</p>
<h1 id="heading-what-is-wireshark">What is Wireshark?</h1>
<p>Wireshark is a sniffer, as well as a packet analyzer.</p>
<p>What does that mean?</p>
<p>You can think of a <strong>sniffer</strong> as a measuring device. We use it to examine what’s going on inside a network cable, or in the air if we are dealing with a wireless network. A sniffer shows us the data that passes through our network card.</p>
<p>But Wireshark does more than that. A sniffer could just display a stream of bits - ones and zeroes, that the network card sees. Wireshark is also a <strong>packer analyzer</strong> that displays lots of meaningful data about the frames that it sees.</p>
<p>Wireshark is an open-source and free tool, and is widely used to analyze network traffic.</p>
<p>Wireshark can be helpful in many cases. It might be helpful for debugging problems in your network, for instance – if you can’t connect from one computer to another, and want to understand what’s going on. </p>
<p>It can also help programmers. For example, imagine that you were implementing a chat program between two clients, and something was not working. In order to understand what exactly is being sent, you may use Wireshark to see the data transmitted over the wire.</p>
<p>So, let’s get to know Wireshark.</p>
<h1 id="heading-how-to-download-and-install-wireshark">How to Download and Install Wireshark</h1>
<p>Start by downloading Wireshark from its official website:</p>
<p><a target="_blank" href="https://www.wireshark.org/#download">https://www.wireshark.org/#download</a></p>
<p>Follow the instructions on the installer and you should be good to go.</p>
<h1 id="heading-how-to-sniff-traffic-with-wireshark">How to Sniff Traffic with Wireshark</h1>
<p>Launch Wireshark, and start by sniffing some data. For that, you can hit <code>Ctrl+K</code> (PC) or <code>Cmd+K</code> (Mac)  to get the <code>Capture Options</code> window. Notice that you can reach this window in other ways. You can go to <code>Capture-&gt;Options</code>. Alternatively, you can click the <code>Capture Options</code> icon.</p>
<p>I encourage you to use keyboard shortcuts and get comfortable with them right from the start, as they'll allow you to save time and work more efficiently.</p>
<p>So, again, I’ve used <code>Ctrl+K</code> (or <code>Cmd+K</code>) and got this screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-208.png" alt="Image" width="600" height="400" loading="lazy">
<em>The <code>Capture Options</code> window in Wireshark (Source: <a target="_blank" href="https://www.youtube.com/watch?v=nbTJXIdEzlo">Brief</a>)</em></p>
<p>Here we can see a list of interfaces, and I happen to have quite a few. Which one is relevant? If you’re not sure at this point, you can look at the <code>Traffic</code> column, and see which interfaces currently have traffic. </p>
<p>Here we can see that <code>Wi-Fi 3</code> has got traffic going through it, as the line is high. Select the relevant network interface, and then hit <code>Enter</code>, or click the button <code>Start</code>.</p>
<p>Let Wireshark sniff the network for a bit, and then stop the sniff using <code>Ctrl+E</code> / <code>Cmd+E</code>. Again, this can be achieved in other ways – such as going to <code>Capture-&gt;Stop</code> or clicking the <code>Stop</code> icon.</p>
<p>Consider the different sections:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-210.png" alt="Image" width="600" height="400" loading="lazy">
<em>Wireshark's sections (Source: <a target="_blank" href="https://www.youtube.com/watch?v=nbTJXIdEzlo">Brief</a>)</em></p>
<p>The section marked in red includes Wireshark’s menu, with all kinds of interesting options.</p>
<p>The main toolbar is marked in blue, providing quick access to some items from the menu.</p>
<p>Next, marked in green, is the <strong>display filter</strong>. We will get back to it shortly, as this is one of the most important features of Wireshark.</p>
<p>Then follows:</p>
<h1 id="heading-the-packet-list-pane">The Packet List Pane</h1>
<p>The packet list pane is marked in orange. It displays a short summary of each packet captured.</p>
<p>(Note: the term Frame belongs to a sequence of bytes in the <a target="_blank" href="https://www.freecodecamp.org/news/the-five-layers-model-explained/">Data Link layer</a>, while a Packet is a sequence of bytes from the <a target="_blank" href="https://www.freecodecamp.org/news/the-five-layers-model-explained/">Network layer</a>. In this post I will use the terms interchangeably, though to be accurate, every packet is a frame, but not every frame is a packet, as there are frames that don't hold network layer data.)</p>
<p>As you can see in the image above, we have a few columns here:</p>
<p>NUMBER (No.) – The number of the packet in the capture file. This number won’t change, even if we use filters. This is just a sequential number – the first frame that you have sniffed gets the number 1, the second frame gets the number 2, and so on.</p>
<p>Time – The timestamp of the packet. It shows how much time has passed from the very first packet we have sniffed until we sniffed the packet in question. Therefore, the time for packet number 1 is always 0.</p>
<p>Source – The address where this packet is coming from. Don’t worry if you don’t understand the format of the addresses just yet, we will cover different addresses in future tutorials.</p>
<p>Destination – The address where this packet is going.</p>
<p>Protocol – The protocol name in a short version. This will be the top protocol – that is, the protocol of the highest layer.</p>
<p>Length – The length of each packet, in bytes.</p>
<p>Info – Additional information about the packet content. This changes according to the protocol.</p>
<p>By clicking on packets in this pane, you control what is displayed in the other two panes which I will now describe.</p>
<h1 id="heading-the-packet-details-pane">The Packet Details Pane</h1>
<p>Click on one of the captured packets. In the example below I clicked on packet number 147:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-211.png" alt="Image" width="600" height="400" loading="lazy">
<em>Selecting a specific packet changes the packet details pane (Source: <a target="_blank" href="https://www.youtube.com/watch?v=nbTJXIdEzlo">Brief</a>)</em></p>
<p>Now, the <strong>packet details pane</strong> displays the packet selected in the packet list pane in more detail. You can see the layers here. </p>
<p>In the example above, we have Ethernet II as the second layer, IPv4 as the third layer, UDP as the fourth layer, and some data as a payload.</p>
<p>When we click on a specific layer, we actually see the <strong>header</strong> of that layer.</p>
<p>Notice that we don’t see the first layer on its own. As a reminder, the first layer is responsible for <strong>transmitting a single bit</strong> – 0 or 1 – over the network (if you need a refresher about the different layers, <a target="_blank" href="https://www.freecodecamp.org/news/the-five-layers-model-explained/">check out this post</a>).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-215.png" alt="Image" width="600" height="400" loading="lazy">
<em>The packet bytes pane in Wireshark (Source: <a target="_blank" href="https://www.youtube.com/watch?v=nbTJXIdEzlo">Brief</a>)</em></p>
<p>Below the packet details pane, we have the <strong>packet bytes pane</strong>. It displays the data from the packet selected in the packet list pane. This is the actual data being sent over the wire. We can see the data in hexadecimal base, as well as ASCII form.</p>
<h1 id="heading-how-to-use-the-display-filter">How to Use the Display Filter</h1>
<p>Wireshark has many different functions, and today we will focus on one thing – the display filter. </p>
<p>As you can see, once you start sniffing data, you get a LOT of traffic. But you definitely don’t want to look at everything. </p>
<p>Recall the example from before – using Wireshark in order to debug a chat program that you’ve implemented. In that case, you would like to see the traffic related to the chat program only.</p>
<p>Let’s say I want to filter only messages sent by the source address of frame number 149 ( <code>192.168.1.3</code> ). I will cover IP addresses in future posts, but for now you can see that it consists four numbers, delimited by a dot:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-217.png" alt="Image" width="600" height="400" loading="lazy">
<em>The <code>display filter</code> in Wireshark (Source: <a target="_blank" href="https://www.youtube.com/watch?v=nbTJXIdEzlo">Brief</a>)</em></p>
<p>Now, even if you don’t know how to filter only packets sent from this IP address, you can use Wireshark to show you how it’s done. </p>
<p>For that, go to the right field we would like to filter – in this case, the source IP address. Then right click -&gt; and choose <code>filter -&gt; Apply as Filter</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-218.png" alt="Image" width="600" height="400" loading="lazy">
<em>Applying a display filter (Source: <a target="_blank" href="https://www.youtube.com/watch?v=nbTJXIdEzlo">Brief</a>)</em></p>
<p>After applying the filter, you only see packets that have been sent from this address. Also, you can look at the display filter line and see the command used. In this way, you can learn about the display filter syntax (in this example, it is <code>ip.src</code> for the IP source address field):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-219.png" alt="Image" width="600" height="400" loading="lazy">
<em>Applying a display filter (Source: <a target="_blank" href="https://www.youtube.com/watch?v=nbTJXIdEzlo">Brief</a>)</em></p>
<p>Now, try to filter only packets that have been sent from this address, and <strong>to</strong> the address <code>172.217.16.142</code> (as in Frame 130 in the image above). How would you do that?</p>
<p>Well, you could go to the relevant field – in this case, the IP destination address. Now, right click -&gt; <code>Apply as Filter</code> -&gt; and select <code>...and Selected</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-220.png" alt="Image" width="600" height="400" loading="lazy">
<em>Applying a display filter (Source: <a target="_blank" href="https://www.youtube.com/watch?v=nbTJXIdEzlo">Brief</a>)</em></p>
<p>If you look at the display filter line after applying this filter:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-221.png" alt="Image" width="600" height="400" loading="lazy">
<em>Applying a display filter (Source: <a target="_blank" href="https://www.youtube.com/watch?v=nbTJXIdEzlo">Brief</a>)</em></p>
<p>You can also learn that you can use the <code>&amp;&amp;</code> operand in order to perform <code>and</code>. You could also write the word <code>and</code>, instead, and get the same result.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-222.png" alt="Image" width="600" height="400" loading="lazy">
<em>Applying multiple conditions using <code>&amp;amp;&amp;amp;</code> or <code>and</code> (Source: <a target="_blank" href="https://www.youtube.com/watch?v=nbTJXIdEzlo">Brief</a>)</em></p>
<h1 id="heading-how-to-use-wireshark-to-research-the-ping-utility">How to Use Wireshark to Research the Ping Utility</h1>
<p><strong>Ping</strong> is a useful utility to check for remote servers’ connectivity.</p>
<p><a target="_blank" href="https://www.howtogeek.com/235101/10-ways-to-open-the-command-prompt-in-windows-10/">This page</a> explains how to use <code>ping</code> in Windows, and <a target="_blank" href="https://macpaw.com/how-to/use-terminal-on-mac">this page</a> explains how to do that in OSX.</p>
<p>Now, we can try to <code>ping &lt;address&gt;</code> using the command line. By default, ping sends <code>4</code> requests and waits for a <strong>pong</strong> answer. If we want it to send a single request, we could use <code>-n 1</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-224.png" alt="Image" width="600" height="400" loading="lazy">
<em>Using the command line to ping Google (Source: <a target="_blank" href="https://www.youtube.com/watch?v=nbTJXIdEzlo">Brief</a>)</em></p>
<p>You can see that Google has responded. The time it took for the message to return was 92 milliseconds. We will learn about the meaning of TTL in future posts.</p>
<p>Ping is useful to determine whether a remote service is available, and how fast it is to reach that service. If it takes a very long time to reach a reliable server such as google.com, we might have a connectivity problem.</p>
<h2 id="heading-try-it-yourself">Try it yourself</h2>
<p>Now, try to use Wireshark to answer the following questions:</p>
<p>1) What protocol does the <strong>ping</strong> utility use?</p>
<p>2) Using only Wireshark, compute the RTT (Round Trip Time) – how long it took since your ping request was sent and until the ping reply was received?</p>
<p>Next, run the following command:</p>
<p><code>ping -n 1 -l 342 www.google.com</code></p>
<p>3) What is the main difference between the packet sent by this command, and the packet sent by the previous command? Where in Wireshark can you see this difference, inspecting the packets?  </p>
<p>4) What is the content (data) provided in the ping request packet? What is the content provided in the ping response packet?</p>
<h2 id="heading-lets-solve-it-together">Let's solve it together</h2>
<p>So the first question is:</p>
<h3 id="heading-what-protocol-does-the-ping-utility-use">What protocol does the ping utility use?</h3>
<p>To answer that question, start sniffing in Wireshark, and simply run the <code>ping</code> command. Stop the sniff, and consider the packets pane:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-225.png" alt="Image" width="600" height="400" loading="lazy">
<em>Sniffing while running ping (source: <a target="_blank" href="https://www.youtube.com/watch?v=B5iEmaZK9xI&amp;t=2s">Brief</a>)</em></p>
<p>Wireshark marks the packets as <code>Echo (ping) request</code> and <code>Echo (ping) reply</code>.</p>
<p>Considering these packets, we can see they consist of <code>Ethernet</code> for the Data Link layer (though that may differ from one network to another), <code>IPv4</code> as the Network layer, and then <code>ICMP</code> as the protocol for Ping itself. So the answer we found is: <strong>ICMP</strong>.</p>
<p>Next question:</p>
<h3 id="heading-using-only-wireshark-compute-the-round-trip-time">Using only Wireshark, compute the Round Trip Time</h3>
<p>Looking at the captured packets, we can see the <code>Time</code> column, and subtract the time of the Pong packet ( <code>7.888...</code> ) from the time of the Ping packet ( <code>7.796...</code>).</p>
<p>So in this case the RTT was: <strong>92 ms</strong>. Of course, the value can be different when you run the <code>ping</code> utility.</p>
<h3 id="heading-what-is-the-main-difference-between-the-packet-sent-by-this-command-and-the-packet-sent-by-the-previous-command">What is the main difference between the packet sent by this command, and the packet sent by the previous command?</h3>
<p>For question number 3, we are asked to run the following command:</p>
<blockquote>
<p>ping -n 1 -l 342 www.google.com</p>
</blockquote>
<p>Looking at the first run of <code>ping</code>, we can see the length of the packets are <code>74</code> bytes:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-225.png" alt="Image" width="600" height="400" loading="lazy">
<em>Sniffing while running ping (source: <a target="_blank" href="https://www.youtube.com/watch?v=B5iEmaZK9xI&amp;t=2s">Brief</a>)</em></p>
<p>Observing the packets sent after running <code>ping</code> with the <code>-l 342</code> argument, we can see that the value is bigger:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-228.png" alt="Image" width="600" height="400" loading="lazy">
<em>Sniffing while running ping (source: <a target="_blank" href="https://www.youtube.com/watch?v=B5iEmaZK9xI&amp;t=2s">Brief</a>)</em></p>
<p>So the main difference is the amount of bytes sent as the data.</p>
<p>Question number four:</p>
<h3 id="heading-what-is-the-content-data-provided-in-the-ping-request-packet">What is the content (data) provided in the ping request packet?</h3>
<h3 id="heading-what-is-the-content-provided-in-the-ping-response-packet">What is the content provided in the ping response packet?</h3>
<p>Click on the request packet to observe the data sent:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-230.png" alt="Image" width="600" height="400" loading="lazy">
<em>Observing the data sent by the <code>ping</code> utility (source: <a target="_blank" href="https://www.youtube.com/watch?v=B5iEmaZK9xI&amp;t=2s">Brief</a>)</em></p>
<p>The answer for the ping request is <code>a</code> through <code>w</code>, over and over again.</p>
<p>Regarding the ping response – it is the same as the request.</p>
<h1 id="heading-summary">Summary</h1>
<p>Wireshark is a wonderful tool for anyone working with Computer Networks. It can help you understand how protocols work and also help you debug applications or network issues. </p>
<p>As you have seen, you can learn how things work by simply running Wireshark in the background while using them and then inspect the traffic. With this tool under your belt, the sky is the limit. </p>
<p>In future tutorials, we will also rely on our knowledge of Wireshark and use it to further understand various concepts in computer networks.</p>
<h2 id="heading-about-the-author">About the Author</h2>
<p><a target="_blank" href="https://www.linkedin.com/in/omer-rosenbaum-034a08b9/">Omer Rosenbaum</a> is <a target="_blank" href="https://swimm.io/">Swimm</a>’s Chief Technology Officer. He's the author of the Brief <a target="_blank" href="https://youtube.com/@BriefVid">YouTube Channel</a>. He's also a cyber training expert and founder of Checkpoint Security Academy. He's the author of <a target="_blank" href="https://data.cyber.org.il/networks/networks.pdf">Computer Networks (in Hebrew)</a>. You can find him on <a target="_blank" href="https://twitter.com/Omer_Ros">Twitter</a>.</p>
<h3 id="heading-additional-references">Additional References</h3>
<ul>
<li><a target="_blank" href="https://www.youtube.com/playlist?list=PL9lx0DXCC4BMS7dB7vsrKI5wzFyVIk2Kg">Computer Networks Playlist - on my Brief channel</a>.</li>
<li><a target="_blank" href="https://www.wireshark.org/">Wireshark's website</a>.</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
