|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +# filter_interfaces function |
| 4 | +filter_interfaces() { |
| 5 | + # This function takes a list of network interfaces as input and filters |
| 6 | + # out loopback interfaces, interfaces without a MAC address, and addresses |
| 7 | + # with a "link" scope or marked as dynamic (from DHCP or router |
| 8 | + # advertisements). The filtered interfaces are returned as an array. |
| 9 | + local network=("$@") |
| 10 | + |
| 11 | + for net in "${network[@]}"; do |
| 12 | + local link_type="$(jq -r '.link_type' <<< "$net")" |
| 13 | + local address="$(jq -r '.address // ""' <<< "$net")" |
| 14 | + local addr_info="$(jq -r '.addr_info | map(select(.scope != "link" and (.dynamic | not)))' <<< "$net")" |
| 15 | + local has_dynamic_address=$(jq -r '.addr_info | any(.dynamic)' <<< "$net") |
| 16 | + |
| 17 | + # echo "Link Type: $link_type -- Address: $address -- Has Dynamic Address: $has_dynamic_address -- Addr Info: $addr_info" |
| 18 | + |
| 19 | + if [[ "$link_type" != "loopback" && -n "$address" && ("$addr_info" != "[]" || "$has_dynamic_address" == "true") ]]; then |
| 20 | + net=$(jq -c --argjson addr_info "$addr_info" '.addr_info = $addr_info' <<< "$net") |
| 21 | + echo "$net" # "return" |
| 22 | + fi |
| 23 | + done |
| 24 | +} |
| 25 | + |
| 26 | +# filter_routes function |
| 27 | +filter_routes() { |
| 28 | + # This function takes a list of routes as input and filters out routes |
| 29 | + # with protocols "dhcp", "kernel", or "ra". The filtered routes are |
| 30 | + # returned as an array. |
| 31 | + local routes=("$@") |
| 32 | + |
| 33 | + for route in "${routes[@]}"; do |
| 34 | + local protocol=$(jq -r '.protocol' <<< "$route") |
| 35 | + if [[ $protocol != "dhcp" && $protocol != "kernel" && $protocol != "ra" ]]; then |
| 36 | + echo "$route" # "return" |
| 37 | + fi |
| 38 | + done |
| 39 | +} |
| 40 | + |
| 41 | +# generate_networkd_units function |
| 42 | +generate_networkd_units() { |
| 43 | + # This function takes the filtered interfaces and routes, along with a |
| 44 | + # directory path. It generates systemd-networkd unit files for each interface, |
| 45 | + # including the configured addresses and routes. The unit files are written |
| 46 | + # to the specified directory with the naming convention 00-<ifname>.network. |
| 47 | + local -n interfaces=$1 |
| 48 | + local -n routes=$2 |
| 49 | + local directory="$3" |
| 50 | + |
| 51 | + mkdir -p "$directory" |
| 52 | + |
| 53 | + for interface in "${interfaces[@]}"; do |
| 54 | + local ifname=$(jq -r '.ifname' <<< "$interface") |
| 55 | + local address=$(jq -r '.address' <<< "$interface") |
| 56 | + local addresses=$(jq -r '.addr_info | map("Address = \(.local)/\(.prefixlen)") | join("\n")' <<< "$interface") |
| 57 | + local route_sections=() |
| 58 | + |
| 59 | + for route in "${routes[@]}"; do |
| 60 | + local dev=$(jq -r '.dev' <<< "$route") |
| 61 | + if [[ $dev == $ifname ]]; then |
| 62 | + local route_section="[Route]" |
| 63 | + local dst=$(jq -r '.dst' <<< "$route") |
| 64 | + if [[ $dst != "default" ]]; then |
| 65 | + route_section+="\nDestination = $dst" |
| 66 | + fi |
| 67 | + local gateway=$(jq -r '.gateway // ""' <<< "$route") |
| 68 | + if [[ -n $gateway ]]; then |
| 69 | + route_section+="\nGateway = $gateway" |
| 70 | + fi |
| 71 | + route_sections+=("$route_section") |
| 72 | + fi |
| 73 | + done |
| 74 | + |
| 75 | + local unit=$(cat <<-EOF |
| 76 | +[Match] |
| 77 | +MACAddress = $address |
| 78 | +
|
| 79 | +[Network] |
| 80 | +DHCP = yes |
| 81 | +LLDP = yes |
| 82 | +IPv6AcceptRA = yes |
| 83 | +MulticastDNS = yes |
| 84 | +
|
| 85 | +$addresses |
| 86 | +$(printf '%s\n' "${route_sections[@]}") |
| 87 | +EOF |
| 88 | +) |
| 89 | + echo -e "$unit" > "$directory/00-$ifname.network" |
| 90 | + done |
| 91 | +} |
| 92 | + |
| 93 | +# main function |
| 94 | +main() { |
| 95 | + if [[ $# -lt 4 ]]; then |
| 96 | + echo "USAGE: $0 addresses routes-v4 routes-v6 networkd-directory" >&2 |
| 97 | + # exit 1 |
| 98 | + return 1 |
| 99 | + fi |
| 100 | + |
| 101 | + local addresses |
| 102 | + readarray -t addresses < <(jq -c '.[]' "$1") # Read JSON data into array |
| 103 | + |
| 104 | + local v4_routes |
| 105 | + readarray -t v4_routes < <(jq -c '.[]' "$2") |
| 106 | + |
| 107 | + local v6_routes |
| 108 | + readarray -t v6_routes < <(jq -c '.[]' "$3") |
| 109 | + |
| 110 | + local networkd_directory="$4" |
| 111 | + |
| 112 | + local relevant_interfaces |
| 113 | + readarray -t relevant_interfaces < <(filter_interfaces "${addresses[@]}") |
| 114 | + |
| 115 | + local relevant_routes |
| 116 | + readarray -t relevant_routes < <(filter_routes "${v4_routes[@]}" "${v6_routes[@]}") |
| 117 | + |
| 118 | + generate_networkd_units relevant_interfaces relevant_routes "$networkd_directory" |
| 119 | +} |
| 120 | + |
| 121 | +main "$@" |
0 commit comments