Hello, everyone! I am Lao Kou! Let’s learn about network configurations together.
Due to work requirements, I need to familiarize myself with the network configurations of gateway devices, so I organized this for easy reference.
I still remember when I was in college, my teacher taught us about computer networks, but I wasn’t paying attention and used the time to learn Java. Therefore, I am not familiar with computer networks, which indirectly led to me being at a loss when encountering network-related issues at work. It was only through reviewing materials and communicating with colleagues that I figured things out. What I wrote here should be of some reference value for beginners.
“The past cannot be admonished, but the future can still be pursued.” This quote comes from the Analects, meaning that past events cannot be advised or changed, but future events can still be amended. Many things need to be personally experienced and cannot be avoided; this may be the fate that is destined! So, rather than avoiding it, it is better to face it calmly, confront your bleak life, and live out your own brilliance!
In today’s rapidly developing technology, almost everyone uses smartphones, and whenever a smartphone connects to the internet, it requires a network.
1. Common Network Configuration Terms
1. IP Address
An IP address is like your home’s “house number” on the internet; with it, data can accurately find your device and transmit information.
Common forms
- IPv4: Four groups of numbers, such as
<span>192.168.1.1</span>(limited in quantity, similar to phone numbers running out). - IPv6: Longer, such as
<span>2001:0db8:85a3::8a2e:0370:7334</span>(solving the shortage issue, the future mainstream).
2. Gateway
A gateway is like your home’s “front door“; all devices wanting to connect to the external internet (like watching videos or browsing the web) must pass through it to enter or exit.
The gateway can unify all your home devices’ “internal IPs” (like <span>192.168.1.18</span>) into a single “public IP“, protecting privacy and saving addresses.
Subnet Mask
A subnet mask is like a “ruler“, used to measure which part of the IP address is the “community name” (network area) and which part is the “house number” (specific device), allowing the router to know whether to deliver locally or send to another province.
For example: <span>192.168.1.18/24</span>
IP Address:<span>192.168.1.18</span>
Subnet Mask:<span>255.255.255.0</span>
Subnet Mask Length:<span>24</span>
<span>Question: Why is the subnet mask 255.255.255.0?</span>

MAC Address
A MAC address is the “ID number” of a device’s network card (globally unique and unchangeable), used to accurately identify each phone/computer/printer in a local network (like your home Wi-Fi) for “face-to-face” direct communication.
2. Hands-on Practice
Let’s modify the network configuration using code. I use Go for development, and the operating system is Ubuntu, so I will use Go and Ubuntu as examples!
The network configuration path for Ubuntu is <span>/etc/netplan/01-network-manager-all.yaml</span>, and different Ubuntu versions may have slightly different names, but it does not affect the configuration usage.
Let’s learn about the parameters of network configuration.
Note: If the gateway device has two <span>LAN</span> ports, you can configure two [<span>LAN1</span> and <span>LAN2</span>], corresponding to network interface names <span>eth0</span> and <span>eth1</span>.
Note:<span>Ethernet</span> can <span>dynamically obtain IP</span> [<span>Dhcp</span>] and <span>statically configure IP</span> [<span>Static</span>].
Field Descriptions
| Field | Description |
|---|---|
<span>version</span> |
Must be <span>2</span> (Netplan configuration version) |
<span>renderer</span> |
Specifies which backend to use, commonly <span>networkd</span> or <span>NetworkManager</span> |
<span>ethernets</span> |
Configures physical network cards |
<span>wifis</span> |
Configures wireless interfaces (requires <span>NetworkManager</span> support) |
Example of Ethernet Parameter Configuration
| Parameter | Type | Example | Description |
|---|---|---|---|
<span>dhcp4</span> |
bool | <span>true</span> / <span>false</span> |
Whether to enable IPv4 DHCP |
<span>dhcp6</span> |
bool | <span>true</span> / <span>false</span> |
Whether to enable IPv6 DHCP |
<span>addresses</span> |
list | <span>[192.168.1.100/24]</span> |
Assign static IP address and subnet mask |
<span>gateway4</span> |
string | <span>192.168.1.1</span> |
IPv4 default gateway |
<span>gateway6</span> |
string | <span>fe80::1</span> |
IPv6 default gateway |
<span>nameservers.addresses</span> |
list | <span>[8.8.8.8, 1.1.1.1]</span> |
DNS server list |
<span>nameservers.search</span> |
list | <span>[example.com]</span> |
DNS search domain list |
<span>optional</span> |
bool | <span>true</span> |
Set as optional (does not affect system startup) |
<span>macaddress</span> |
string | <span>aa:bb:cc:dd:ee:ff</span> |
Specify the MAC address of the network card |
<span>mtu</span> |
int | <span>1500</span> |
Set MTU value |
<span>routes.to</span> |
list | <span>10.0.0.0/8</span> |
Target subnet |
<span>routes.via</span> |
list | <span>192.168.1.1</span> |
Next hop address (gateway), packets will be sent to this gateway for forwarding |
<span>routes.metric</span> |
list | <span>100</span> |
Routing priority, the smaller the number, the higher the priority. Among multiple matching paths, the one with the lower metric will be preferred |
Example of Wi-Fi Parameter Configuration
| Parameter | Type | Example | Description |
|---|---|---|---|
<span>dhcp4</span> |
boolean | <span>true</span> / <span>false</span> |
Whether to enable IPv4 DHCP |
<span>dhcp6</span> |
boolean | <span>true</span> / <span>false</span> |
Whether to enable IPv6 DHCP |
<span>optional</span> |
boolean | <span>true</span> |
Mark the interface as “non-critical”, not blocking on startup |
<span>addresses</span> |
list | <span>[192.168.1.100/24]</span> |
Assign static IP address |
<span>gateway4</span> |
string | <span>192.168.1.1</span> |
Set IPv4 default gateway |
<span>gateway6</span> |
string | <span>fe80::1</span> |
Set IPv6 default gateway |
<span>nameservers.addresses</span> |
list | <span>[8.8.8.8, 1.1.1.1]</span> |
Set DNS servers |
<span>macaddress</span> |
string | <span>aa:bb:cc:dd:ee:ff</span> |
Set MAC address (MAC Spoofing) |
<span>routes.to</span> |
list | <span>10.0.0.0/8</span> |
Target subnet |
<span>routes.via</span> |
list | <span>192.168.1.1</span> |
Next hop address (gateway), packets will be sent to this gateway for forwarding |
<span>routes.metric</span> |
list | <span>100</span> |
Routing priority, the smaller the number, the higher the priority. Among multiple matching paths, the one with the lower metric will be preferred |
<span>access-points.<SSID>.password</span> |
string | <span>"12345678"</span> |
Wi-Fi password, supports WPA/WPA2 |
<span>access-points.<SSID>.mode</span> |
string | <span>"infrastructure"</span> / <span>"adhoc"</span> |
Connection mode (infrastructure or point-to-point) |
<span>access-points.<SSID>.bssid</span> |
string | <span>aa:bb:cc:dd:ee:ff</span> |
MAC address of the specific AP to connect to (used only in multi-AP scenarios) |
<span>access-points.<SSID>.band</span> |
string | <span>"2.4GHz"</span> / <span>"5GHz"</span> |
Frequency band (optional) |
<span>access-points.<SSID>.channel</span> |
int | <span>6</span> |
Channel (used only for Ad-Hoc) |
<span>access-points.<SSID>.hidden</span> |
boolean | <span>true</span> |
Whether the SSID is a hidden Wi-Fi |
net.go
package main
import (
"errors"
"os"
"os/exec"
"runtime"
"strings"
"gopkg.in/yaml.v3"
)
const (
// Default network configuration file path
DEFAULT_NETPLAN_CONFIG_PATH = "/etc/netplan/01-network-manager-all.yaml"
// LAN1 port 1
LAN1 = "eth0"
// LAN2 port 2
LAN2 = "eth1"
)
type NetworkConfig struct {
Address string `json:"address"`
Gateway string `json:"gateway"`
Dns string `json:"dns"`
MacAddress string `json:"macAddress"`
}
type NetPlanConfig struct {
Network struct {
// Version must be 2, indicating the version of Netplan configuration
Version int8 `yaml:"version,omitempty"`
// Renderer specifies which backend to use, commonly networkd or NetworkManager
// NetworkManager is suitable for desktop environments
// networkd is suitable for server environments
Renderer string `yaml:"renderer,omitempty"`
// Ethernets is a map, with keys as network card names and values as Ethernet configurations
// For example: `"eth0": { ... }`
// The network card names can be physical or virtual
// For example: `"eth0"`, `"eth1"`, `"wlan0"`, etc.
Ethernets map[string]*Ethernet `yaml:"ethernets,omitempty"`
// If you need to configure wireless network cards, use the `wifis` field
Wifis map[string]*Wifi `yaml:"wifis,omitempty"`
} `yaml:"network,omitempty"`
}
// Wifi wireless network interface configuration structure【Wi-Fi】
type Wifi struct {
// DHCP4 and DHCP6 indicate whether to enable IPv4 and IPv6 DHCP respectively
Dhcp4 bool `yaml:"dhcp4"`
Dhcp6 bool `yaml:"dhcp6,omitempty"`
// Optional indicates whether this interface is optional; set to true to not block on startup
Optional bool `yaml:"optional,omitempty"`
// Address configures the IP address
Addresses []string `yaml:"addresses,omitempty"`
// Gateway4 and Gateway6 indicate the default gateways for IPv4 and IPv6 respectively
Gateway4 string `yaml:"gateway4,omitempty"`
Gateway6 string `yaml:"gateway6,omitempty"`
// Nameservers contains DNS server addresses
Nameservers struct {
// Addresses is the list of DNS server addresses
Addresses []string `yaml:"addresses,omitempty"`
} `yaml:"nameservers,omitempty"`
// MacAddress is the MAC address of the network card
MacAddress string `yaml:"macaddress,omitempty"`
// Routes is a list of routes, each containing a target address, gateway, and priority
Routes Route `yaml:"routes,omitempty"`
// AccessPoints is a map, with keys as SSIDs and values as AccessPoint configurations
AccessPoints map[string]AccessPoint `yaml:"access-points,omitempty"`
}
// Ethernet network card structure【Ethernet】
type Ethernet struct {
// DHCP4 and DHCP6 indicate whether to enable IPv4 and IPv6 DHCP respectively
DHCP4 bool `yaml:"dhcp4"`
DHCP6 bool `yaml:"dhcp6,omitempty"`
// Addresses is an array of strings representing assigned static IP addresses and subnet masks
Addresses []string `yaml:"addresses,omitempty"`
// Gateway4 and Gateway6 indicate the default gateways for IPv4 and IPv6 respectively
Gateway4 string `yaml:"gateway4,omitempty"`
Gateway6 string `yaml:"gateway6,omitempty"`
// Nameservers contains DNS server addresses and search domains
Nameservers struct {
// Addresses is the list of DNS server addresses
Addresses []string `yaml:"addresses,omitempty"`
// Search is the list of DNS search domains
Search []string `yaml:"search,omitempty"`
} `yaml:"nameservers,omitempty"`
// Routes is a list of routes, each containing a target address, gateway, and priority
Routes Route `yaml:"routes,omitempty"`
// Optional indicates whether this interface is optional; set to true to not block on startup
Optional bool `yaml:"optional,omitempty"`
// MacAddress is the MAC address of the network card
MacAddress string `yaml:"macaddress,omitempty"`
// Mtu is the MTU of the network card
Mtu int `yaml:"mtu,omitempty"`
}
// Route structure
type Route struct {
// To is the target address or subnet
To string `yaml:"to,omitempty"`
// Via is the gateway address for the route
Via string `yaml:"via,omitempty"`
// Metric is the routing priority; the smaller the number, the higher the priority
Metric int `yaml:"metric,omitempty"`
}
// AccessPoint wireless access point configuration structure
type AccessPoint struct {
// Mode is the connection mode, possible values are "infrastructure" (infrastructure mode) or "adhoc" (point-to-point mode)
Mode string `yaml:"mode,omitempty"`
// Password is the Wi-Fi password, supports WPA/WPA2
Password string `yaml:"password,omitempty"`
// Bssid is the MAC address of the access point, usually used to connect to a specific AP
Bssid string `yaml:"bssid,omitempty"`
// Band is the wireless frequency band, possible values are "2.4GHz" or "5GHz"
Band string `yaml:"band,omitempty"`
// Channel is the wireless channel, usually used for Ad-Hoc mode
Channel int `yaml:"channel,omitempty"`
// Hidden indicates whether the SSID is hidden, usually used for Ad-Hoc mode
Hidden bool `yaml:"hidden,omitempty"`
}
func NewDefaultNetPlanConfig() *NetPlanConfig {
netConfig := &NetPlanConfig{}
netConfig.Network.Version = 2
netConfig.Network.Renderer = "NetworkManager"
// Two network ports
netConfig.Network.Ethernets = make(map[string]*Ethernet, 2)
netConfig.Network.Ethernets[LAN1] = &Ethernet{}
netConfig.Network.Ethernets[LAN2] = &Ethernet{}
return netConfig
}
func SaveNetPlanConfig(buf []byte, path string) error {
err := os.WriteFile(path, buf, 0644)
if err != nil {
return errors.New("Failed to write network configuration file, error message: " + err.Error())
}
return nil
}
func ApplyNetPlanConfig() error {
err := validateOS()
if err != nil {
return err
}
err = exec.Command("netplan", "apply").Run()
if err != nil {
return errors.New("Failed to apply network configuration, error message: " + err.Error())
}
return nil
}
func ReadNetPlanConfig(path string) (*NetPlanConfig, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, errors.New("Failed to read network configuration file, error message: " + err.Error())
}
netConfig := &NetPlanConfig{}
err = yaml.Unmarshal(data, netConfig)
if err != nil {
return nil, errors.New("Failed to deserialize network configuration, error message: " + err.Error())
}
return netConfig, nil
}
func GetMacAddress() (string, error) {
err := validateOS()
if err != nil {
return "", err
}
output, err := exec.Command("sh", "-c", `ip link show eth0 | awk '/ether/ {print $2}'`).Output()
if err != nil {
return "", errors.New("Failed to get MAC address, error message: " + err.Error())
}
return strings.TrimSpace(string(output)), nil
}
func GetIpAddress() (string, error) {
err := validateOS()
if err != nil {
return "", err
}
output, err := exec.Command("sh", "-c", `ip addr show eth0 | grep "inet " | awk '{print $2}' | cut -d'/' -f1`).Output()
if err != nil {
return "", errors.New("Failed to get IP address, error message: " + err.Error())
}
return strings.TrimSpace(string(output)), nil
}
func GetGateway() (string, error) {
err := validateOS()
if err != nil {
return "", err
}
output, err := exec.Command("sh", "-c", `ip route | grep default | grep eth0 | awk '{print $3}'`).Output()
if err != nil {
return "", errors.New("Failed to get gateway, error message: " + err.Error())
}
return strings.TrimSpace(string(output)), nil
}
func GetNetmask() (string, error) {
err := validateOS()
if err != nil {
return "", err
}
output, err := exec.Command("sh", "-c", `ip addr show eth0 | grep "inet " | awk '{print $2}' | cut -d'/' -f2`).Output()
if err != nil {
return "", errors.New("Failed to get subnet mask length, error message: " + err.Error())
}
return strings.TrimSpace(string(output)), nil
}
func GetNetworkConfig(path string) (*NetworkConfig, error) {
config, err := getNetPlanConfig(path)
if err != nil {
return nil, err
}
ethernet := config.Network.Ethernets[LAN1]
return &NetworkConfig{
Address: ethernet.Addresses[0],
Gateway: ethernet.Gateway4,
Dns: strings.Join(ethernet.Nameservers.Addresses, ","),
MacAddress: ethernet.MacAddress,
}, nil
}
func getNetPlanConfig(path string) (*NetPlanConfig, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, errors.New("Failed to get network configuration, error message: " + err.Error())
}
netConfig := &NetPlanConfig{}
err = yaml.Unmarshal(data, netConfig)
return netConfig, nil
}
func validateOS() error {
if runtime.GOOS != "linux" {
return errors.New("Gateway does not support this operation on " + runtime.GOOS + " operating system")
}
return nil
}
net_test.go
package main
import (
"fmt"
"gopkg.in/yaml.v3"
"testing"
)
func TestNetPlanConfig(t *testing.T) {
netConfig := NewDefaultNetPlanConfig()
netConfig.Network.Ethernets[LAN1].DHCP4 = true
netConfig.Network.Ethernets[LAN1].MacAddress = "22:03:xz:2f:a2:1a"
netConfig.Network.Ethernets[LAN2].DHCP4 = false
netConfig.Network.Ethernets[LAN2].MacAddress = "22:03:xz:2f:a2:1a"
netConfig.Network.Ethernets[LAN2].Addresses = []string{"100.100.1.10/24"}
netConfig.Network.Ethernets[LAN2].Gateway4 = "100.100.1.1"
netConfig.Network.Ethernets[LAN2].Nameservers.Addresses = []string{"8.8.8.8", "114.114.114.114"}
out, err := yaml.Marshal(netConfig)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(string(out))
err = SaveNetPlanConfig(out, "ethernets.yaml")
if err != nil {
fmt.Println(err.Error())
}
err = ApplyNetPlanConfig()
if err != nil {
fmt.Println(err.Error())
}
config, err := ReadNetPlanConfig("ethernets.yaml")
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(config.Network.Ethernets[LAN1].DHCP4)
config.Network.Ethernets[LAN1].DHCP4 = false
config.Network.Ethernets[LAN1].Addresses = []string{"192.168.1.10/24"}
config.Network.Ethernets[LAN1].Gateway4 = "192.168.1.1"
config.Network.Ethernets[LAN1].Nameservers.Addresses = []string{"8.8.8.8", "114.114.114.114"}
out, err = yaml.Marshal(config)
err = SaveNetPlanConfig(out, "ethernets.yaml")
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(GetNetmask())
fmt.Println(GetMacAddress())
fmt.Println(GetIpAddress())
fmt.Println(GetGateway())
networkConfig, err := GetNetworkConfig("ethernets.yaml")
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(networkConfig.Dns)
fmt.Println(networkConfig.Gateway)
fmt.Println(networkConfig.Address)
fmt.Println(networkConfig.MacAddress)
}
Run Results
network:
version: 2
renderer: NetworkManager
ethernets:
eth0:
dhcp4: true
macaddress: 22:03:xz:2f:a2:1a
eth1:
dhcp4: false
addresses:
- 100.100.1.10/24
gateway4: 100.100.1.1
nameservers:
addresses:
- 8.8.8.8
- 114.114.114.114
macaddress: 22:03:xz:2f:a2:1a
The gateway does not support this operation on the Windows operating system.
true
The gateway does not support this operation on the Windows operating system.
The gateway does not support this operation on the Windows operating system.
The gateway does not support this operation on the Windows operating system.
The gateway does not support this operation on the Windows operating system.
8.8.8.8,114.114.114.114
192.168.1.1
192.168.1.10/24
22:03:xz:2f:a2:1a
Processor architectures are divided into <span>amd64</span> and <span>arm64</span>, so there are some differences in Go packaging.
We can check the processor architecture using the <span>arch</span> command.
The gateway devices I have debugged include <span>armv7l</span><span>aarch64</span><span>x86_64</span> among others.
For <span>armv7l</span>【<span>32-bit</span>】, we can only modify it through commands, using <span>Go</span> to execute commands to modify the configuration.
<span>Static IP Configuration</span>
# IP Address: 192.168.1.18/24
# Gateway: 192.168.1.1
# DNS: 8.8.8.8
nmcli connection delete "eth0 static"
nmcli connection add con-name "eth0 static" ifname eth0 type ethernet
nmcli connection modify "eth0 static" ipv4.method manual ipv4.addresses 192.168.1.18/24 ipv4.gateway 192.168.1.1 ipv4.dns 8.8.8.8
nmcli connection up "eth0 static"
nmcli connection delete "eth0 dhcp"
<span>Dynamic IP Configuration</span>
nmcli connection delete "eth0 dhcp"
nmcli connection add con-name "eth0 dhcp" ifname eth0 type ethernet
nmcli connection modify "eth0 dhcp" ipv4.method auto
nmcli connection up "eth0 dhcp"
nmcli connection delete "eth0 static"
I am Lao Kou, see you next time!