April 15, 2024

We’re working for a shopper that produces hearth vehicles. 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 checks.

DHCP server and shopper

A serious situation with Docker is the necessity to assign IP addresses for containers. It’s impractical to depend on computerized deal with assignments managed by Docker or to manually set addresses when containers are began. The structure meant for IoT edge ought to be certain that the state of the machine might 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 complete structure – see the Router container in our earlier textual content. It’s also value contemplating the situation the place an exterior supplier desires to hook up with the sting machine with additional 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 appears 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 answer will depend on a DHCP server and a DHCP shopper. At startup, the script answerable for working the Docker picture will name the DHCP shopper and obtain details about the MAC deal with and IP deal with the container may have.

In the end, we wish to get a everlasting configuration that’s saved as a file or some easy database for the above. This can give us an immutable configuration for the essential parameters of the Docker container. To attach the MAC deal with, IP deal with, and Docker container, we suggest including the identify of the potential Docker container to the file. This can create a hyperlink for the three parts that uniquely identifies the Docker container.

When the script begins, it queries the DHCP server for a potential obtainable IP deal with and checks beforehand if there may be already a lease for the IP/MAC deal with decided from the Docker container identify.

This achieves a configuration that’s proof against 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 package deal. It is a pattern configuration you’ll be able to alter on 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;
  possibility domain-name-servers 8.8.8.8, 8.8.4.4;
  possibility routers 10.0.1.3;
  possibility 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;
  possibility domain-name-servers 8.8.8.8, 8.8.4.4;
  possibility routers 10.0.2.3;
  possibility 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 deal with swimming pools for every VLAN in our community.

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

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

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

possibility routers – this assigns a default gateway for the DHCP purchasers. Gadgets 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.

possibility subnet-mask – this specifies the subnet masks to be assigned to DHCP purchasers, which on this case is 255.255.255.0. It determines the community portion of an IP deal with.

default-lease-time – specifies how lengthy, in seconds, a DHCP lease will probably 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 deal with. Right here, it’s 7200 seconds or 2 hours.

DHCP Consumer

In our situation, all new utility containers are added to the system by way of bash instructions executed on the Host – the firetruck’s predominant laptop 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 deal with from the DHCP server (as dynamic IP) and arrange a container with the deal with configured as static IP. To attain this, we want a shell-friendly DHCP shopper. We’ve determined to go together with a Python script that may be referred to as when creating new containers.

DHCP Consumer Instance (Python)

See feedback within the scripts beneath 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, sort=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 supply 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 supply (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, sort=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 deal with
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 deal with
    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 discuss our use case.

The enterprise requirement is so as to add one other machine to the sting – maybe a thermal imaging digital camera. Our assumption is to ensure as totally computerized onboarding of the machine in our system as potential. Including a brand new machine 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 deal with from the DHCP server. The IP deal with is, after all, depending on the VLAN wherein the brand new machine will probably be situated.

In abstract, it’s straightforward to see that plugging in a brand new machine at this level simply signifies that the IP deal with is routinely assigned and sure. The brand new machine 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 companies, reminiscent of discovering close by gadgets for knowledge alternate or sending a command to all gadgets in a community.

Multicast, then again, permits for the environment friendly distribution of information to a bunch of gadgets on a community. This may be helpful in situations the place the identical knowledge must be despatched to a number of gadgets on the identical time, reminiscent of a reside video stream or a software program replace.

One objective of the structure was to offer a seamless, remoted, LAN-like atmosphere for every utility. Due to this fact, it was important to allow purposes to make use of not solely direct, IP, or DNS-based communication but in addition 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 assets obtainable.

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

Let’s examine whether or not these strategies 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 plain 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 feature units the SO_BROADCAST socket possibility, permitting the UDP packet to be despatched to all gadgets on the native community phase.

-s 10.0.1.3 – This feature units the supply IP deal with of the UDP packet to 10.0.1.3.

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

10.0.1.255 – That is the vacation spot IP deal with of the UDP packet, which is the published deal with for the native community phase.

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

Please word that each supply and vacation spot addresses belong to VLAN 1. Due to this fact, the datagram is distributed by way of the eth0 interface to this VLAN solely.

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

Multicast

Let’s concentrate on 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 possibility is essential if it’s good to allow ICMP echo requests to the published deal with contained in the container. For instance, in case your containerized utility depends on UDP broadcast for service discovery or communication with different containers, you could have to set this parameter to 0 to permit ICMP echo requests to be despatched and acquired on the community.

With out setting this parameter to 0, your containerized utility could not have the ability to talk correctly with different containers on the community or could expertise sudden habits as a consequence of ICMP echo requests being ignored. Due to this fact, the --sysctl internet.ipv4.icmp_echo_ignore_broadcasts=0 possibility might be essential in sure Docker use instances the place ICMP echo requests to the published deal with are wanted.

Utilization instance

Run the command beneath 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 word that the IP deal with of the multicast group doesn’t belong to the VLAN 1 deal with area.

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 may ping the deal with from Machine 1 to confirm the group has been created.

ping -I eth0 -t 2 233.54.12.234

As you’ll be able to see, an interface parameter is required with the ping command to implement utilizing the right outgoing interface. You can even 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 word you need to setup the path to keep away from sending packets to “unknown community” on to the router.

Now, you’ll be able to sort the message on Device1 and use tcpdump on Container1 to see the incoming message.

tcpdump -i eth0 -Xavvv

Abstract

These days, a significant problem confronted by builders and prospects is to ensure most safety whereas making certain compatibility and openness to vary for edge gadgets. As a part of IoT, it’s crucial to remember the fact that the delivered answer could also be prolonged sooner or later with further {hardware} modules, and thus, the atmosphere into which this module will probably be deployed have to be prepared for adjustments.

This downside asks the non-trivial query of the best way to meet enterprise necessities whereas considering all the rules from requirements from {hardware} distributors or the same old authorized requirements.

Translating the introduced structure into a hearth vehicles context, all the necessities from the introduction relating to isolation and modularity of the atmosphere have been met. Every truck has the flexibility to increase the related {hardware} whereas sustaining safety protocols. As well as, the Docker photos that work with the {hardware} know solely their personal scope and the router’s scope.

The proposed answer offers a prepared reply on the best way to get hold of a change-ready atmosphere that meets safety necessities. A key ingredient of the structure is to ensure communication for purposes solely within the VLAN area wherein they’re situated.

This fashion, any modification mustn’t have an effect on already current processes on the sting facet. It’s also value detailing the position performed by the Router element. With it, we assure a technique to talk between Docker containers whereas sustaining a configuration that lets you management community visitors.

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

Summarizing the introduced answer, one mustn’t overlook about purposes in different industries as nicely. The concept of unbiased Docker photos and modularity for {hardware} permits utility even within the Automotive and high-reliability areas, the place using a number of gadgets, not essentially from the identical provider, is required.

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