Skip to content

Commit

Permalink
work on network
Browse files Browse the repository at this point in the history
  • Loading branch information
raoulh committed Nov 1, 2024
1 parent b6f7377 commit 4d63e9a
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 30 deletions.
27 changes: 24 additions & 3 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM debian:12-slim as dev
FROM debian:12-slim

RUN apt -y update && \
apt -y upgrade && \
Expand All @@ -9,7 +9,7 @@ RUN apt -y update && \
inotify-tools curl wget ifupdown2 jq build-essential git \
unzip zip cmake automake autoconf libtool autopoint gettext \
tar gzip zsh vim nano sudo zstd less gnupg ripgrep gdb cgdb locales \
systemd systemd-resolved systemd-sysv
systemd systemd-resolved systemd-sysv dbus iproute2 iputils-ping

RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
sed -i -e 's/# fr_FR.UTF-8 UTF-8/fr_FR.UTF-8 UTF-8/' /etc/locale.gen && \
Expand Down Expand Up @@ -39,4 +39,25 @@ RUN echo "\n\
\n\
set show-all-if-ambiguous on \n\
set completion-ignore-case on \n\
" >> /etc/inputrc
" >> /etc/inputrc

RUN echo "\n\
[Match]\n\
Name=calaos-*\n\
\n\
[Network]\n\
DHCP=yes\n\
" > /etc/systemd/network/calaos.network

COPY setup_veth.sh /usr/local/bin/setup_veth.sh
RUN chmod +x /usr/local/bin/setup_veth.sh
COPY setup-veth.service /etc/systemd/system/setup-veth.service
RUN systemctl enable setup-veth.service

RUN systemctl enable setup-veth.service
RUN systemctl enable systemd-resolved.service
RUN systemctl enable systemd-networkd.service

ENV container docker
STOPSIGNAL SIGRTMIN+3
CMD ["/lib/systemd/systemd", "--system", "--unit=basic.target"]
25 changes: 20 additions & 5 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,31 @@
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cpptools-extension-pack",
"ms-vscode.makefile-tools",
"lizebang.bash-extension-pack",
"ms-vscode.cmake-tools"
"ms-vscode.cpptools-extension-pack",
"ms-vscode.makefile-tools",
"lizebang.bash-extension-pack",
"ms-vscode.cmake-tools",
"ms-azuretools.vscode-docker",
"golang.go",
"jinliming2.vscode-go-template",
"mesonbuild.mesonbuild",
"esbenp.prettier-vscode",
"foxundermoon.shell-format"
]
}
},

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
"remoteUser": "root",

"runArgs": ["--privileged"]
"runArgs": [
"--privileged",
"--cap-add=SYS_ADMIN",
"--tmpfs", "/run",
"--tmpfs", "/run/lock",
"-v", "/sys/fs/cgroup:/sys/fs/cgroup"
],

"overrideCommand": false,
"privileged": true
}
11 changes: 11 additions & 0 deletions .devcontainer/setup-veth.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[Unit]
Description=Setup virtual ethernet interfaces (veth)
Before=systemd-networkd.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/setup_veth.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
11 changes: 11 additions & 0 deletions .devcontainer/setup_veth.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash
# Create 4 pairs of veth interfaces

for i in {0..1}; do
veth_in="calaos-${i}-0"
veth_out="calaos-${i}-1"

ip link add "$veth_in" type veth peer name "$veth_out"
ip link set "$veth_in" up
ip link set "$veth_out" up
done
4 changes: 4 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ func NewApp() (a *AppServer, err error) {
return a.apiNetIntfList(c)
})

api.Get("/network/dns", func(c *fiber.Ctx) error {
return a.apiNetDNS(c)
})

//Force an update check
api.Get("/update/check", func(c *fiber.Ctx) error {
return a.apiUpdateCheck(c)
Expand Down
16 changes: 16 additions & 0 deletions app/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,19 @@ func (a *AppServer) apiNetIntfList(c *fiber.Ctx) (err error) {
"output": nets,
})
}

func (a *AppServer) apiNetDNS(c *fiber.Ctx) (err error) {
dns, err := models.GetDNSConfig()
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": true,
"msg": err.Error(),
})
}

return c.Status(fiber.StatusOK).JSON(fiber.Map{
"error": false,
"msg": "ok",
"output": dns,
})
}
2 changes: 1 addition & 1 deletion debian/[email protected]
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[Unit]
Description=Inputattach tool for serial2USB converter on %i
BindTo=dev-%i.device
BindsTo=dev-%i.device
After=dev-%i.device xserver-nodm.service

[Service]
Expand Down
146 changes: 125 additions & 21 deletions models/network.go
Original file line number Diff line number Diff line change
@@ -1,49 +1,153 @@
package models

import "net"
import (
"bufio"
"encoding/json"
"fmt"
"os/exec"
"regexp"
"strings"
)

type NetIntf struct {
Name string `json:"name"`
IPv4 string `json:"ipv4"`
Mask string `json:"mask"`
Gateway string `json:"gateway"`
IPv6 string `json:"ipv6"`
MAC string `json:"mac"`
IsLoopback bool `json:"is_loopback"`
State string `json:"state"`
}

type DNSConfig struct {
Interface string `json:"interface"`
DNSServers []string `json:"dns_servers"`
SearchDomains []string `json:"search_domains"`
}

type RawNetInterface struct {
Name string `json:"Name"`
Flags int `json:"Flags"`
IPv4 string `json:"IPv4Address"`
IPv4Mask int `json:"IPv4Mask"`
IPv6 string `json:"IPv6LinkLocalAddress"`
MAC string `json:"HardwareAddress"`
State string `json:"KernelOperationalStateString"`
Addresses []struct {
Family int `json:"Family"`
Scope string `json:"ScopeString"`
Prefix int `json:"PrefixLength"`
} `json:"Addresses"`
Routes []struct {
Family int `json:"Family"`
Type string `json:"TypeString"`
Gateway string `json:"Gateway"`
Dest string `json:"Destination"`
PrefixLen int `json:"DestinationPrefixLength"`
} `json:"Routes"`
}

type RawDNSConfig struct {
Link int `json:"Link"`
CurrentDNS []string `json:"CurrentDNSServer"`
SearchDomains []string `json:"Domains"`
LLMNR string `json:"LLMNR"`
MulticastDNS string `json:"MulticastDNS"`
DNSSEC string `json:"DNSSEC"`
InterfaceName string `json:"InterfaceName"`
}

func parseMask(prefixLen int) string {
mask := (0xFFFFFFFF << (32 - prefixLen)) & 0xFFFFFFFF
return fmt.Sprintf("%d.%d.%d.%d", (mask>>24)&0xFF, (mask>>16)&0xFF, (mask>>8)&0xFF, mask&0xFF)
}

func GetAllNetInterfaces() (nets []*NetIntf, err error) {
ifaces, err := net.Interfaces()
cmd := exec.Command("/usr/bin/networkctl", "list", "--json=short")
output, err := cmd.Output()
if err != nil {
return nil, err
}

for _, iface := range ifaces {
addrs, err := iface.Addrs()
if err != nil {
return nil, err
var rawInterfaces []RawNetInterface
if err := json.Unmarshal(output, &rawInterfaces); err != nil {
return nil, err
}

for _, rawIntf := range rawInterfaces {
netIntf := &NetIntf{
Name: rawIntf.Name,
MAC: rawIntf.MAC,
State: rawIntf.State,
IsLoopback: (rawIntf.Flags & 0x8) != 0, // check IFF_LOOPBACK
}

intf := &NetIntf{
Name: iface.Name,
IsLoopback: iface.Flags&net.FlagLoopback != 0,
MAC: iface.HardwareAddr.String(),
// Look for IPv4 address and mask
for _, addr := range rawIntf.Addresses {
if addr.Family == 2 { // IPv4
netIntf.IPv4 = fmt.Sprintf("%d.%d.%d.%d", addr.Scope[0], addr.Scope[1], addr.Scope[2], addr.Scope[3])
netIntf.Mask = parseMask(addr.Prefix)
break
}
}

for _, addr := range addrs {
ipNet, ok := addr.(*net.IPNet)
if !ok {
continue
// Look for IPv6 address
for _, addr := range rawIntf.Addresses {
if addr.Family == 10 { // IPv6
netIntf.IPv6 = rawIntf.IPv6
break
}
}

// Skip IPv6 addresses
if ipNet.IP.To4() == nil {
intf.IPv6 = ipNet.IP.String()
} else if ipNet.IP.To16() != nil {
intf.IPv4 = ipNet.IP.String()
// Look for default gateway
for _, route := range rawIntf.Routes {
if route.Type == "unicast" && route.Gateway != "" {
netIntf.Gateway = route.Gateway
break
}
}

nets = append(nets, intf)
nets = append(nets, netIntf)
}

return nets, nil
}

func GetDNSConfig() ([]*DNSConfig, error) {
cmd := exec.Command("/usr/bin/resolvectl", "status")
output, err := cmd.Output()
if err != nil {
return nil, err
}

var dnsConfigs []*DNSConfig
var currentConfig *DNSConfig

scanner := bufio.NewScanner(strings.NewReader(string(output)))
dnsServerRegex := regexp.MustCompile(`DNS Servers? ([\d.]+)`)
interfaceRegex := regexp.MustCompile(`Link (\d+) \(([^)]+)\)`)

for scanner.Scan() {
line := scanner.Text()

if strings.HasPrefix(line, "Global") {
currentConfig = &DNSConfig{Interface: "global"}
dnsConfigs = append(dnsConfigs, currentConfig)
} else if matches := interfaceRegex.FindStringSubmatch(line); len(matches) == 3 {
currentConfig = &DNSConfig{Interface: matches[2]}
dnsConfigs = append(dnsConfigs, currentConfig)
}

if dnsServerRegex.MatchString(line) {
server := dnsServerRegex.FindStringSubmatch(line)[1]
currentConfig.DNSServers = append(currentConfig.DNSServers, server)
}
}

if err := scanner.Err(); err != nil {
return nil, err
}

return
return dnsConfigs, nil
}

0 comments on commit 4d63e9a

Please sign in to comment.