f-25: dhcp: fill db with dhcp data

Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
GnomeZworc 2026-04-26 18:08:04 +02:00
commit 5ee2ba1669
Signed by: nicolas.boufideline
GPG key ID: 4406BBBF8845D632
5 changed files with 41 additions and 13 deletions

19
internal/dhcp/db.go Normal file
View file

@ -0,0 +1,19 @@
package dhcp
import (
"git.g3e.fr/syonad/two/pkg/db/kv"
"github.com/dgraph-io/badger/v4"
)
func StoreDHCPEntries(db *badger.DB, subnetName string, entries map[string]string) error {
for ip, mac := range entries {
if err := kv.AddInDB(db, "subnet/"+subnetName+"/dhcp/"+ip, mac); err != nil {
return err
}
}
return nil
}
func GetMACForIP(db *badger.DB, subnetName, ip string) (string, error) {
return kv.GetFromDB(db, "subnet/"+subnetName+"/dhcp/"+ip)
}

View file

@ -61,7 +61,7 @@ func newConf(t *testing.T, cidr string) Config {
func TestGenerateConfig_CreatesFile(t *testing.T) { func TestGenerateConfig_CreatesFile(t *testing.T) {
conf := newConf(t, "192.168.1.0/29") // 6 hôtes conf := newConf(t, "192.168.1.0/29") // 6 hôtes
path, err := GenerateConfig(conf) path, _, err := GenerateConfig(conf)
if err != nil { if err != nil {
t.Fatalf("GenerateConfig a échoué : %v", err) t.Fatalf("GenerateConfig a échoué : %v", err)
} }
@ -73,7 +73,7 @@ func TestGenerateConfig_CreatesFile(t *testing.T) {
func TestGenerateConfig_FilenameMatchesName(t *testing.T) { func TestGenerateConfig_FilenameMatchesName(t *testing.T) {
conf := newConf(t, "192.168.1.0/29") conf := newConf(t, "192.168.1.0/29")
path, err := GenerateConfig(conf) path, _, err := GenerateConfig(conf)
if err != nil { if err != nil {
t.Fatalf("GenerateConfig a échoué : %v", err) t.Fatalf("GenerateConfig a échoué : %v", err)
} }
@ -86,7 +86,7 @@ func TestGenerateConfig_FilenameMatchesName(t *testing.T) {
func TestGenerateConfig_ContainsGateway(t *testing.T) { func TestGenerateConfig_ContainsGateway(t *testing.T) {
conf := newConf(t, "192.168.1.0/29") conf := newConf(t, "192.168.1.0/29")
path, _ := GenerateConfig(conf) path, _, _ := GenerateConfig(conf)
content, _ := os.ReadFile(path) content, _ := os.ReadFile(path)
if !strings.Contains(string(content), "dhcp-option=3,192.168.1.1") { if !strings.Contains(string(content), "dhcp-option=3,192.168.1.1") {
@ -102,7 +102,7 @@ func TestGenerateConfig_ContainsDhcpRange(t *testing.T) {
Name: "vpc1", Name: "vpc1",
ConfDir: t.TempDir(), ConfDir: t.TempDir(),
} }
path, _ := GenerateConfig(conf) path, _, _ := GenerateConfig(conf)
content, _ := os.ReadFile(path) content, _ := os.ReadFile(path)
if !strings.Contains(string(content), "dhcp-range=10.10.0.0,static,255.255.255.0,12h") { if !strings.Contains(string(content), "dhcp-range=10.10.0.0,static,255.255.255.0,12h") {
@ -113,7 +113,7 @@ func TestGenerateConfig_ContainsDhcpRange(t *testing.T) {
func TestGenerateConfig_OneHostEntryPerIP(t *testing.T) { func TestGenerateConfig_OneHostEntryPerIP(t *testing.T) {
// /29 = réseau + broadcast + 6 hôtes → 8 adresses // /29 = réseau + broadcast + 6 hôtes → 8 adresses
conf := newConf(t, "10.0.0.0/29") conf := newConf(t, "10.0.0.0/29")
path, _ := GenerateConfig(conf) path, _, _ := GenerateConfig(conf)
content, _ := os.ReadFile(path) content, _ := os.ReadFile(path)
lines := strings.Split(string(content), "\n") lines := strings.Split(string(content), "\n")
@ -131,7 +131,7 @@ func TestGenerateConfig_OneHostEntryPerIP(t *testing.T) {
func TestGenerateConfig_MACPrefix(t *testing.T) { func TestGenerateConfig_MACPrefix(t *testing.T) {
conf := newConf(t, "10.0.0.0/30") // 4 adresses conf := newConf(t, "10.0.0.0/30") // 4 adresses
path, _ := GenerateConfig(conf) path, _, _ := GenerateConfig(conf)
content, _ := os.ReadFile(path) content, _ := os.ReadFile(path)
if !strings.Contains(string(content), "00:22:33:") { if !strings.Contains(string(content), "00:22:33:") {
@ -148,7 +148,7 @@ func TestGenerateConfig_CreatesConfDir(t *testing.T) {
Name: "net", Name: "net",
ConfDir: dir, ConfDir: dir,
} }
if _, err := GenerateConfig(conf); err != nil { if _, _, err := GenerateConfig(conf); err != nil {
t.Fatalf("GenerateConfig devrait créer les répertoires manquants : %v", err) t.Fatalf("GenerateConfig devrait créer les répertoires manquants : %v", err)
} }
if _, err := os.Stat(dir); os.IsNotExist(err) { if _, err := os.Stat(dir); os.IsNotExist(err) {

View file

@ -8,7 +8,7 @@ import (
"strings" "strings"
) )
func GenerateConfig(c Config) (string, error) { func GenerateConfig(c Config) (string, map[string]string, error) {
mask := fmt.Sprintf("%d.%d.%d.%d", c.Network.Mask[0], c.Network.Mask[1], c.Network.Mask[2], c.Network.Mask[3]) mask := fmt.Sprintf("%d.%d.%d.%d", c.Network.Mask[0], c.Network.Mask[1], c.Network.Mask[2], c.Network.Mask[3])
var sb strings.Builder var sb strings.Builder
@ -17,18 +17,20 @@ func GenerateConfig(c Config) (string, error) {
fmt.Fprintf(&sb, "dhcp-option=3,%s\n", c.Gateway.String()) fmt.Fprintf(&sb, "dhcp-option=3,%s\n", c.Gateway.String())
fmt.Fprintf(&sb, "dhcp-option=6,1.1.1.1,8.8.8.8\n\n") fmt.Fprintf(&sb, "dhcp-option=6,1.1.1.1,8.8.8.8\n\n")
entries := make(map[string]string)
i := 0 i := 0
for ip := cloneIP(c.Network.IP); c.Network.Contains(ip); incrementIP(ip) { for ip := cloneIP(c.Network.IP); c.Network.Contains(ip); incrementIP(ip) {
fmt.Fprintf(&sb, "dhcp-host=00:22:33:%02X:%02X:%02X,%s\n", mac := fmt.Sprintf("00:22:33:%02X:%02X:%02X", (i>>16)&0xFF, (i>>8)&0xFF, i&0xFF)
(i>>16)&0xFF, (i>>8)&0xFF, i&0xFF, ip) fmt.Fprintf(&sb, "dhcp-host=%s,%s\n", mac, ip)
entries[ip.String()] = mac
i++ i++
} }
outPath := filepath.Join(c.ConfDir, c.Name+".conf") outPath := filepath.Join(c.ConfDir, c.Name+".conf")
if err := os.MkdirAll(c.ConfDir, 0755); err != nil { if err := os.MkdirAll(c.ConfDir, 0755); err != nil {
return "", err return "", nil, err
} }
return outPath, os.WriteFile(outPath, []byte(sb.String()), 0644) return outPath, entries, os.WriteFile(outPath, []byte(sb.String()), 0644)
} }
func incrementIP(ip net.IP) { func incrementIP(ip net.IP) {

View file

@ -101,9 +101,13 @@ func CreateSubnet(db *badger.DB, subnetName string) error {
Name: d.vpc + "_" + d.bridge, Name: d.vpc + "_" + d.bridge,
ConfDir: "/etc/dnsmasq.d", ConfDir: "/etc/dnsmasq.d",
} }
if _, err := dhcp.GenerateConfig(conf); err != nil { _, entries, err := dhcp.GenerateConfig(conf)
if err != nil {
return fmt.Errorf("generate dhcp config: %w", err) return fmt.Errorf("generate dhcp config: %w", err)
} }
if err := dhcp.StoreDHCPEntries(db, subnetName, entries); err != nil {
return fmt.Errorf("store dhcp entries: %w", err)
}
svc, err := systemd.New() svc, err := systemd.New()
if err != nil { if err != nil {

View file

@ -42,6 +42,9 @@ func DeleteSubnet(db *badger.DB, subnetName string) error {
if err := os.Remove("/etc/dnsmasq.d/" + d.vpc + "_" + d.bridge + ".conf"); err != nil && !os.IsNotExist(err) { if err := os.Remove("/etc/dnsmasq.d/" + d.vpc + "_" + d.bridge + ".conf"); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("remove dnsmasq config: %w", err) return fmt.Errorf("remove dnsmasq config: %w", err)
} }
if err := kv.DeleteInDB(db, "subnet/"+subnetName+"/dhcp"); err != nil {
return fmt.Errorf("delete dhcp entries: %w", err)
}
if err := ebtables.DeleteARPToGateway(d.bridge, d.gatewayIP.String()); err != nil { if err := ebtables.DeleteARPToGateway(d.bridge, d.gatewayIP.String()); err != nil {
return fmt.Errorf("delete ebtables arp rule: %w", err) return fmt.Errorf("delete ebtables arp rule: %w", err)