Only select dynamic ip addresses
This commit is contained in:
parent
ac040ac6f7
commit
a484431d13
4 changed files with 157 additions and 7 deletions
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"os"
|
||||
)
|
||||
|
||||
|
@ -13,9 +14,39 @@ type HealthchecksConfig struct {
|
|||
PingKey string `json:"ping_key"`
|
||||
}
|
||||
|
||||
type DNSMasqConfig struct {
|
||||
DHCPRangeStart netip.Addr
|
||||
DHCPRangeEnd netip.Addr
|
||||
LeasesPath string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
HealthchecksConfig `json:"healthchecks"`
|
||||
LeasesPath string `json:"leases_path"`
|
||||
DNSMasqConfigFile string `json:"dnsmasq_config"`
|
||||
DNSMasqConfig
|
||||
}
|
||||
|
||||
func (c *Config) parseDNSMasqConf() error {
|
||||
dnsMasqRootContent, err := os.ReadFile(c.DNSMasqConfigFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read dnsmasq config: %w", err)
|
||||
}
|
||||
|
||||
dnsmasqRawConf, err := parseDNSMasqOptions(string(dnsMasqRootContent))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse dnsmasq config: %w", err)
|
||||
}
|
||||
c.LeasesPath = dnsmasqRawConf.leaseFile
|
||||
c.DHCPRangeStart, err = netip.ParseAddr(dnsmasqRawConf.rangeStart)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse dhcp range start: %w", err)
|
||||
}
|
||||
c.DHCPRangeEnd, err = netip.ParseAddr(dnsmasqRawConf.rangeEnd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse dhcp range end: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func defaultConfig() *Config {
|
||||
|
@ -23,7 +54,7 @@ func defaultConfig() *Config {
|
|||
HealthchecksConfig: HealthchecksConfig{
|
||||
Enabled: false,
|
||||
},
|
||||
LeasesPath: "/var/lib/misc/dnsmasq.leases",
|
||||
DNSMasqConfigFile: "etc/dnsmasq.conf",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +62,8 @@ func New(path string) (*Config, error) {
|
|||
fileContent, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return defaultConfig(), nil
|
||||
conf := defaultConfig()
|
||||
return conf, conf.parseDNSMasqConf()
|
||||
}
|
||||
return nil, fmt.Errorf("failed to read config file %w", err)
|
||||
}
|
||||
|
@ -40,5 +72,5 @@ func New(path string) (*Config, error) {
|
|||
if err := json.Unmarshal(fileContent, &c); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse config file: %w", err)
|
||||
}
|
||||
return &c, nil
|
||||
return &c, c.parseDNSMasqConf()
|
||||
}
|
||||
|
|
96
internal/config/dnsmasq.go
Normal file
96
internal/config/dnsmasq.go
Normal file
|
@ -0,0 +1,96 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
leaseFileKey = "dhcp-leasefile"
|
||||
rangeKey = "dhcp-range"
|
||||
confFileKey = "conf-file"
|
||||
confDirKey = "conf-dir"
|
||||
)
|
||||
|
||||
func tryParseLineOption(line, key string) (string, bool) {
|
||||
if !strings.HasPrefix(line, key) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
_, val, found := strings.Cut(line, "=")
|
||||
return val, found
|
||||
}
|
||||
|
||||
type dnsmasqConfOptions struct {
|
||||
leaseFile string
|
||||
rangeStart string
|
||||
rangeEnd string
|
||||
}
|
||||
|
||||
func defaultDNSMasqOptions() map[string]string {
|
||||
return map[string]string{
|
||||
confDirKey: "/etc/dnsmasq.d",
|
||||
confFileKey: "",
|
||||
leaseFileKey: "/var/lib/misc/dnsmasq.leases",
|
||||
rangeKey: "",
|
||||
}
|
||||
}
|
||||
|
||||
func parseDNSMasqConfFile(content string, options map[string]string) {
|
||||
for _, l := range strings.Split(content, "\n") {
|
||||
for key := range options {
|
||||
newVal, found := tryParseLineOption(l, key)
|
||||
if found {
|
||||
options[key] = newVal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseDNSMasqOptions(rootFileContent string) (dnsmasqConfOptions, error) {
|
||||
rawOptions := defaultDNSMasqOptions()
|
||||
|
||||
// start with parsing the root file
|
||||
parseDNSMasqConfFile(rootFileContent, rawOptions)
|
||||
|
||||
// get all additional conf files in the provided directory
|
||||
confDir := rawOptions[confDirKey]
|
||||
if confDir != "" {
|
||||
entries, err := os.ReadDir(confDir)
|
||||
if err != nil {
|
||||
return dnsmasqConfOptions{}, fmt.Errorf("failed to get list of additional config files: %w", err)
|
||||
}
|
||||
for _, e := range entries {
|
||||
if e.IsDir() || !strings.HasSuffix(e.Name(), ".conf") {
|
||||
continue
|
||||
}
|
||||
fileContent, err := os.ReadFile(path.Join(confDir, e.Name()))
|
||||
if err != nil {
|
||||
return dnsmasqConfOptions{}, fmt.Errorf("failed to read sub config file: %w", err)
|
||||
}
|
||||
parseDNSMasqConfFile(string(fileContent), rawOptions)
|
||||
}
|
||||
}
|
||||
|
||||
// get any additional config file
|
||||
if additionalFile := rawOptions[confFileKey]; additionalFile != "" {
|
||||
filecontent, err := os.ReadFile(additionalFile)
|
||||
if err != nil {
|
||||
return dnsmasqConfOptions{}, fmt.Errorf("failed to read additional config file: %w", err)
|
||||
}
|
||||
parseDNSMasqConfFile(string(filecontent), rawOptions)
|
||||
}
|
||||
|
||||
dhcpRange := strings.Split(rawOptions[rangeKey], ",")
|
||||
if len(dhcpRange) < 2 {
|
||||
return dnsmasqConfOptions{}, fmt.Errorf("invalid value for DHCP range: %s", rawOptions[rangeKey])
|
||||
}
|
||||
|
||||
return dnsmasqConfOptions{
|
||||
leaseFile: rawOptions[leaseFileKey],
|
||||
rangeStart: dhcpRange[0],
|
||||
rangeEnd: dhcpRange[1],
|
||||
}, nil
|
||||
}
|
|
@ -2,6 +2,7 @@ package dnsmasq
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -11,7 +12,7 @@ import (
|
|||
type Lease struct {
|
||||
ExpireDate time.Time
|
||||
Mac string
|
||||
IP string
|
||||
IP netip.Addr
|
||||
Hostname string
|
||||
ClientID string
|
||||
}
|
||||
|
@ -31,10 +32,15 @@ func parseLeaseLine(rawLine string) (*Lease, error) {
|
|||
return nil, fmt.Errorf("unexpected unix timestamp value %s", lineValues[0])
|
||||
}
|
||||
|
||||
ip, err := netip.ParseAddr(lineValues[2])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unexpected IP address: %s: %w", lineValues[2], err)
|
||||
}
|
||||
|
||||
return &Lease{
|
||||
ExpireDate: time.Unix(int64(expireTimeInt), 0),
|
||||
Mac: lineValues[1],
|
||||
IP: lineValues[2],
|
||||
IP: ip,
|
||||
Hostname: lineValues[3],
|
||||
ClientID: lineValues[4],
|
||||
}, nil
|
||||
|
@ -59,3 +65,19 @@ func GetLeases(leasesPath string) ([]*Lease, error) {
|
|||
}
|
||||
return leases, nil
|
||||
}
|
||||
|
||||
func GetDynamicLeases(leasesPath string, dhcpStart, dhcpEnd netip.Addr) ([]*Lease, error) {
|
||||
allLeases, err := GetLeases(leasesPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filteredLeases := []*Lease{}
|
||||
for _, l := range allLeases {
|
||||
if l.IP.Less(dhcpEnd) && dhcpStart.Less(l.IP) {
|
||||
filteredLeases = append(filteredLeases, l)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredLeases, nil
|
||||
}
|
||||
|
|
2
main.go
2
main.go
|
@ -31,7 +31,7 @@ func main() {
|
|||
fmt.Fprintf(os.Stderr, "Failed to notify process start: %s\n", err)
|
||||
}
|
||||
|
||||
leases, err := dnsmasq.GetLeases(conf.LeasesPath)
|
||||
leases, err := dnsmasq.GetDynamicLeases(conf.LeasesPath, conf.DHCPRangeStart, conf.DHCPRangeEnd)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to parse leases: %s\n", err)
|
||||
if err := healthchecks.Failure(context.Background(), conf.HealthchecksConfig, healtchecksClt, check, "failed to parse lease file"); err != nil {
|
||||
|
|
Loading…
Reference in a new issue