April 24, 2024

We’re working for a shopper that produces fireplace vans. There’s a listing of necessities and the structure proposal within the first article and a step-by-step implementation of the prototype in the second. This time, we’re going to shut the subject with DHCP implementation and UDP assessments.

DHCP server and shopper

A serious difficulty with Docker is the necessity to assign IP addresses for containers. It’s impractical to depend on computerized handle assignments managed by Docker or to manually set addresses when containers are began. The structure meant for IoT edge ought to be sure that the state of the system will be simply reproduced even after an influence failure or reboot.

It might even be essential to set fastened addresses for containers that would be the reference level for the whole structure – see the Router container in our earlier textual content. Additionally it is value contemplating the situation the place an exterior supplier desires to hook up with the sting system with further gadgets. As a part of the collaboration, it could be crucial to offer immutable IP addresses, e.g., for IP discovery service.

Our job is to offer a service to assign IP addresses from configurable swimming pools for each bodily and digital gadgets in VLANs. It feels like DHCP and certainly, it’s DHCP, however it’s not so easy with Docker. Sadly, Docker makes use of its personal addressing mechanism that can not be linked to the community DHCP server.

The proposed resolution will depend on a DHCP server and a DHCP shopper. At startup, the script chargeable for working the Docker picture will name the DHCP shopper and obtain details about the MAC handle and IP handle the container may have.

Finally, we wish to get a everlasting configuration that’s saved as a file or some easy database for the above. It will give us an immutable configuration for the fundamental parameters of the Docker container. To attach the MAC handle, IP handle, and Docker container, we suggest including the title of the potential Docker container to the document. It will create a hyperlink for the three components that uniquely identifies the Docker container.

When the script begins, it queries the DHCP server for a doable accessible IP handle and checks beforehand if there may be already a lease for the IP/MAC handle decided from the Docker container title.

This achieves a configuration that’s immune to IP conflicts and ensures the reusability of beforehand assigned IP addresses.

DHCP server

For our use-case, we’ve determined to depend on isc-dhcp-server bundle. This can be a pattern configuration you may alter to your wants.

dhcpd.conf


authoritative;
one-lease-per-client true;

subnet 10.0.1.0 netmask 255.255.255.0 
  vary 10.0.1.2 10.0.1.200;
  choice domain-name-servers 8.8.8.8, 8.8.4.4;
  choice routers 10.0.1.3;
  choice subnet-mask 255.255.255.0;
  default-lease-time 3600;
  max-lease-time 7200;

subnet 10.0.2.0 netmask 255.255.255.0 
  vary 10.0.2.2 10.0.1.200;
  choice domain-name-servers 8.8.8.8, 8.8.4.4;
  choice routers 10.0.2.3;
  choice subnet-mask 255.255.255.0;
  default-lease-time 3600;
  max-lease-time 7200;

Right here is the breakdown for every line within the talked about configuration. There are two subnets configured with two handle swimming pools for every VLAN in our community.

authoritative – this directive implies that the DHCP server is the authoritative supply for the community. If a shopper queries with an IP handle that it was given by one other DHCP server, this server will inform the shopper that the IP handle is invalid, successfully forcing the shopper to ask for a brand new IP handle.

one-lease-per-client – this ensures that every shopper will get just one lease at a time. This helps keep away from eventualities the place a single shopper may find yourself consuming a number of IP addresses, resulting in a diminished accessible IP pool.

choice domain-name-servers – this assigns DNS servers to the DHCP shoppers. On this case, it’s utilizing Google’s public DNS servers (8.8.8.8 and eight.8.4.4).

choice routers – this assigns a default gateway for the DHCP shoppers. Units on this community will use 10.0.1.3 as their manner out of the native community, more likely to attain the web or different networks.

choice subnet-mask – this specifies the subnet masks to be assigned to DHCP shoppers, which on this case is 255.255.255.0. It determines the community portion of an IP handle.

default-lease-time – specifies how lengthy, in seconds, a DHCP lease might be legitimate if the shopper doesn’t ask for a selected lease time. Right here, it’s set to 3600 seconds, which is equal to 1 hour.

max-lease-time – this units the utmost period of time, in seconds, a shopper can lease an IP handle. Right here, it’s 7200 seconds or 2 hours.

DHCP Consumer

In our situation, all new software containers are added to the system through bash instructions executed on the Host – the firetruck’s predominant pc or Raspberry PI in our prototype. See the earlier chapter for including containers instructions reference. The command requires IP addresses and gateways for every container.

Our method is to acquire an handle from the DHCP server (as dynamic IP) and arrange a container with the handle configured as static IP. To attain this, we want a shell-friendly DHCP shopper. We’ve determined to go along with a Python script that may be referred to as when creating new containers.

DHCP Consumer Instance (Python)

See feedback within the scripts under for explanations of every block.

from scapy.layers.dhcp import BOOTP, DHCP
from scapy.layers.inet import UDP, IP, ICMP
from scapy.layers.l2 import Ether
from scapy.sendrecv import sendp, sniff

# Sendind discovery packet for DHCP 
def locate_dhcp(src_mac_addr):
    packet = Ether(dst="ff:ff:ff:ff:ff:ff", src=src_mac_addr, kind=0x0800) / IP(src="https://grapeup.com/weblog/fleet-management-with-aws-iot-overcoming-limitations-of-docker-virtual-networks/0.0.0.0", dst="255.255.255.255") / 
          UDP(dport=67, sport=68) / BOOTP(op=1, chaddr=src_mac_addr) / DHCP(choices=[('message-type', 'discover'), 'end'])
    sendp(packet, iface="enp2s0")

# Receiving provide by filtering out packets packet[DHCP].choices[0][1] == 2
def capture_offer():
    return sniff(iface="enp2s0", filter="port 68 and port 67",
                 stop_filter=lambda packet: BOOTP in packet and packet[BOOTP].op == 2 and packet[DHCP].choices[0][1] == 2,
                 timeout=5)

# Transmitting packets with accepted provide (IP) from DHCP
def transmit_request(src_mac_addr, req_ip, srv_ip):
    packet = Ether(dst="ff:ff:ff:ff:ff:ff", src=src_mac_addr, kind=0x0800) / IP(src="https://grapeup.com/weblog/fleet-management-with-aws-iot-overcoming-limitations-of-docker-virtual-networks/0.0.0.0", dst="255.255.255.255") / 
          UDP(dport=67, sport=68) / BOOTP(op=1, chaddr=src_mac_addr) / 
          DHCP(choices=[('message-type', 'request'), ("client_id", src_mac_addr), ("requested_addr", req_ip),
                        ("server_id", srv_ip), 'end'])
    sendp(packet, iface="enp2s0")

# Studying acknowledgement from DHCP. Filtering out packet[BOOTP].op == 2 and packet[DHCP].choices[0][1] == 5 and ports 68/67
def capture_acknowledgement():
    return sniff(iface="enp2s0", filter="port 68 and port 67",
                 stop_filter=lambda packet: BOOTP in packet and packet[BOOTP].op == 2 and packet[DHCP].choices[0][1] == 5,
                 timeout=5)

# Ping provided IP handle
def transmit_test_packet(src_mac_addr, src_ip_addr, dst_mac_addr, dst_ip_addr):
    packet = Ether(src=src_mac_addr, dst=dst_mac_addr) / IP(src=src_ip_addr, dst=dst_ip_addr) / ICMP()
    sendp(packet, iface="enp2s0")
 

if __name__ == "__main__":
    # dummy mac handle
    mac_addr = "aa:bb:cc:11:22:33"
    print("START")
    print("SEND: Uncover")
    locate_dhcp(mac_addr)
    print("RECEIVE: Supply")
    received_packets = capture_offer()
    server_mac_addr = received_packets[0]["Ether"].src
    bootp_response = received_packets[0]["BOOTP"]
    server_ip_addr = bootp_response.siaddr
    offered_ip_addr = bootp_response.yiaddr
    print("OFFER:", offered_ip_addr)
    print("SEND: Request for", offered_ip_addr)
    transmit_request(mac_addr, offered_ip_addr, server_ip_addr)
    print("RECEIVE: Acknowledge")
    received_packets2 = capture_acknowledgement()
    print("ACKNOWLEDGE:", offered_ip_addr)
    print("SEND: Take a look at IP Packet")
    transmit_test_packet(mac_addr, offered_ip_addr, server_mac_addr, server_ip_addr)
    print("END")

Let’s speak about our use case.

The enterprise requirement is so as to add one other system to the sting – maybe a thermal imaging digicam. Our assumption is to ensure as totally computerized onboarding of the system in our system as doable. Including a brand new system may even imply, in our case, connecting it to the customer-provided Docker container.

Our anticipated result’s to get a course of that registers the brand new Docker container with the assigned IP handle from the DHCP server. The IP handle is, after all, depending on the VLAN by which the brand new system might be situated.

In abstract, it’s straightforward to see that plugging in a brand new system at this level simply implies that the IP handle is mechanically assigned and sure. The brand new system is conscious of the place the Router container is situated – so communication is assured from the very starting.

UDP broadcast and multicast setup

Broadcast UDP is a technique for sending a message to all gadgets on a community phase, which permits for environment friendly communication and discovery of different gadgets on the identical community. In an IoT context, this can be utilized for the invention of gadgets and providers, comparable to discovering close by gadgets for knowledge change or sending a command to all gadgets in a community.

Multicast, however, permits for the environment friendly distribution of knowledge to a bunch of gadgets on a community. This may be helpful in eventualities the place the identical knowledge must be despatched to a number of gadgets on the identical time, comparable to a stay video stream or a software program replace.

One objective of the structure was to offer a seamless, remoted, LAN-like atmosphere for every software. Subsequently, it was important to allow functions to make use of not solely direct, IP, or DNS-based communication but additionally to permit multicasting and broadcasting messages. These protocols allow gadgets to speak with one another in a manner that’s scalable and bandwidth-efficient, which is essential for IoT techniques the place there could also be restricted community sources accessible.

The introduced structure offers an answer for dockerized functions that use UDP broadcast/multicast. The router Docker container atmosphere is meant to host functions which might be to distribute knowledge to different containers within the method.

Let’s verify whether or not these methods can be found to our edge networks.

Broadcast

The take a look at part ought to begin on the Container1 container with an enabled UDP listener. For that, run the command.

nc -ulp 5000

The command makes use of the netcat (nc) utility to hear (-l) for incoming UDP (-u) datagrams on port 5000 (-p 5000).

Then, let’s produce a message on the Router container.

echo -n "foo" | nc -uv -b -s 10.0.1.3 -w1 10.0.1.255 5000

The command above is an instruction that makes use of the echo and netcat to ship a UDP datagram containing the string “foo” to all gadgets on the native community phase.

Breaking down the command:

echo -n “foo” – This command prints the string “foo” to straightforward output with no trailing newline character.

nc – The nc command is used to create community connections and can be utilized for a lot of functions, together with sending and receiving knowledge over a community.

-uv – These choices specify that nc ought to use UDP because the transport protocol and that it must be run in verbose mode.

-b – This selection units the SO_BROADCAST socket choice, permitting the UDP packet to be despatched to all gadgets on the native community phase.

-s 10.0.1.3 – This selection units the supply IP handle of the UDP packet to 10.0.1.3.

-w1 – This selection units the timeout for the nc command to 1 second.

10.0.1.255 – That is the vacation spot IP handle of the UDP packet, which is the printed handle for the native community phase.

5000 – That is the vacation spot port quantity for the UDP packet.

Please be aware that each supply and vacation spot addresses belong to VLAN 1. Subsequently, the datagram is shipped through the eth0 interface to this VLAN solely.

The anticipated result’s the docker container Container1 receiving the message from the Router container through UDP broadcast.

Multicast

Let’s deal with Docker Container parameters specified when creating containers (Docker containers [execute on host] sub-chapter within the earlier article). Within the context of Docker containers, the --sysctl internet.ipv4.icmp_echo_ignore_broadcasts=0 choice is essential if it’s good to allow ICMP echo requests to the printed handle contained in the container. For instance, in case your containerized software depends on UDP broadcast for service discovery or communication with different containers, chances are you’ll must set this parameter to 0 to permit ICMP echo requests to be despatched and obtained on the community.

With out setting this parameter to 0, your containerized software could not be capable to talk correctly with different containers on the community or could expertise surprising habits resulting from ICMP echo requests being ignored. Subsequently, the --sysctl internet.ipv4.icmp_echo_ignore_broadcasts=0 choice will be essential in sure Docker use circumstances the place ICMP echo requests to the printed handle are wanted.

Utilization instance

Run the command under within the container Container1 (see earlier chapter for naming references). We use socat, which is a command line utility that establishes a bidirectional byte stream and transfers knowledge between them. Please be aware that the IP handle of the multicast group doesn’t belong to the VLAN 1 handle house.

socat -u UDP4-RECV:22001,ip-add-membership=233.54.12.234:eth0 /dev/null &

Then, add the path to the multicast group.

ip route add 233.54.12.234/32 dev eth0

You’ll be able to ping the handle from System 1 to confirm the group has been created.

ping -I eth0 -t 2 233.54.12.234

As you may see, an interface parameter is required with the ping command to implement utilizing the proper outgoing interface. You too can restrict the TTL parameter (-t 2) to confirm the route size to the multicast group.

Now, use socat on Device1 to open the connection contained in the group.

ip route add 233.54.12.234/32 dev eth0
socat STDIO UDP-DATAGRAM:233.54.12.234:22001

Please be aware you need to setup the path to keep away from sending packets to “unknown community” on to the router.

Now, you may kind the message on Device1 and use tcpdump on Container1 to see the incoming message.

tcpdump -i eth0 -Xavvv

Abstract

These days, a serious problem confronted by builders and clients is to ensure most safety whereas guaranteeing compatibility and openness to vary for edge gadgets. As a part of IoT, it’s crucial to remember the fact that the delivered resolution could also be prolonged sooner or later with extra {hardware} modules, and thus, the atmosphere into which this module might be deployed should be prepared for adjustments.

This drawback asks the non-trivial query of easy methods to meet enterprise necessities whereas bearing in mind all the rules from requirements from {hardware} distributors or the same old authorized requirements.

Translating the introduced structure into a fireplace vans context, all the necessities from the introduction relating to isolation and modularity of the atmosphere have been met. Every truck has the power to develop the linked {hardware} whereas sustaining safety protocols. As well as, the Docker photographs that work with the {hardware} know solely their non-public scope and the router’s scope.

The proposed resolution offers a prepared reply on easy methods to receive a change-ready atmosphere that meets safety necessities. A key factor of the structure is to ensure communication for functions solely within the VLAN house by which they’re situated.

This fashion, any modification mustn’t have an effect on already current processes on the sting aspect. Additionally it is value detailing the position performed by the Router element. With it, we assure a strategy to talk between Docker containers whereas sustaining a configuration that permits you to management community site visitors.

We’ve got additionally included an answer for UDP Broadcast / Multicast communication. Present requirements amongst {hardware} embrace options that transmit knowledge through the usual. Because of this if, for instance, we’re ready for emergency knowledge on a tool, we should even be able to deal with Broadcasts and be sure that packets are consumed solely by these parts which might be designed for this objective.

Summarizing the introduced resolution, one mustn’t neglect about functions in different industries as nicely. The concept of impartial Docker photographs and modularity for {hardware} permits software even within the Automotive and high-reliability areas, the place the usage of a number of gadgets, not essentially from the identical provider, is required.

We encourage you to consider additional potential functions and thanks for taking the time to learn.