From ef74b1c529cc7593a3ac3cca700c9b87f89ad482 Mon Sep 17 00:00:00 2001 From: vaninpetr <> Date: Fri, 6 Jan 2023 23:17:17 +0300 Subject: [PATCH] initial commit --- README.md | 33 +++++++++++++ config.yml | 8 ++++ src/main.go | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 README.md create mode 100644 config.yml create mode 100644 src/main.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..3c77fb7 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# Regela ARP proxy + +### Very simple, lazy method to configure arp tables +#### Written for our Virtuozzo's Community OS servers by Elizar [@Regela](https://sources.krechet.tech/Regela) + +#### Include example config file in .yml, where is: +- name: *interfacename* +- addresses: *list of ips on interfacename* + +#### Usage: move config.yum in folder /etc/RegelaArpProxy/ and run binary + +``` +~# RegelaArpProxy --help +Usage of RegelaArpProxy: + -example + -i string + Config File (default "/etc/RegelaArpProxy/config.yml") + + ~# RegelaArpProxy -example +interfaces: +- name: br0 + addresses: + - 10.10.100.10 + - 10.10.100.11 + - 10.10.100.12 + - 10.10.100.13 +- name: br1 + addresses: + - 10.10.101.10 + - 10.10.101.11 + - 10.10.101.12 + - 10.10.101.13 +``` \ No newline at end of file diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..45b0dc4 --- /dev/null +++ b/config.yml @@ -0,0 +1,8 @@ +interfaces: +- name: vlan101 + addresses: + - 10.10.3.2 + - 10.10.3.5 +- name: vlan102 + addresses: + - 10.10.116.11 diff --git a/src/main.go b/src/main.go new file mode 100644 index 0000000..2de779c --- /dev/null +++ b/src/main.go @@ -0,0 +1,135 @@ +package main + +import ( + "bytes" + "flag" + "fmt" + "github.com/goccy/go-yaml" + "github.com/mdlayher/arp" + "github.com/mdlayher/ethernet" + "io" + "io/ioutil" + "log" + "net" + "os" + "time" +) + +type Interface struct{ + Name string + Addresses []net.IP +} + +type Settings struct { + Interfaces []Interface +} + + +var ( + configFile = flag.String("i", "/etc/RegelaArpProxy/config.yml", "Config File") + printExampleFlag = flag.Bool("example",false,"") + + +) + +func task(iface Interface){ + ifi, err := net.InterfaceByName(iface.Name) + if err != nil { + log.Fatal(err) + } + + client, err := arp.Dial(ifi) + if err != nil { + log.Fatalf("couldn't create ARP client: %s", err) + } + + // Handle ARP requests bound for designated IPv4 address, using proxy ARP + // to indicate that the address belongs to this machine + for { + pkt, eth, err := client.Read() + if err != nil { + if err == io.EOF { + log.Println("EOF") + break + } + log.Fatalf("error processing ARP requests: %s", err) + } + + // Ignore ARP replies + if pkt.Operation != arp.OperationRequest { + continue + } + + // Ignore ARP requests which are not broadcast or bound directly for + // this machine + if !bytes.Equal(eth.Destination, ethernet.Broadcast) /*&& !bytes.Equal(eth.Destination, ifi.HardwareAddr)*/ { + continue + } + + log.Printf("request: who-has %s? tell %s (%s)", pkt.TargetIP, pkt.SenderIP, pkt.SenderHardwareAddr) + + // Ignore ARP requests which do not indicate the target IP + for _, ip := range iface.Addresses { + if pkt.TargetIP.Equal(ip) { + log.Printf(" reply: %s is-at %s", ip, ifi.HardwareAddr) + if err := client.Reply(pkt, ifi.HardwareAddr, ip); err != nil { + log.Fatal(err) + } + } + } + } +} + + +func printExample() { + settings := Settings{ + Interfaces: []Interface{ + { + Name: "br0", + Addresses: []net.IP{ + net.ParseIP("10.10.100.10"), + net.ParseIP("10.10.100.11"), + net.ParseIP("10.10.100.12"), + net.ParseIP("10.10.100.13"), + }, + }, + { + Name: "br1", + Addresses: []net.IP{ + net.ParseIP("10.10.101.10"), + net.ParseIP("10.10.101.11"), + net.ParseIP("10.10.101.12"), + net.ParseIP("10.10.101.13"), + }, + }, + }, + } + out, _ := yaml.Marshal(settings) + fmt.Printf("%s",out) +} + +func main() { + flag.Parse() + + if *printExampleFlag{ + printExample() + os.Exit(0) + } + + cf, err := ioutil.ReadFile(*configFile) + if err != nil { + log.Fatalf("Read configuration error: %s", err.Error()) + } + + settings := Settings{} + err = yaml.Unmarshal(cf,&settings) + for _, iface := range settings.Interfaces { + go task(iface) + } + for { + time.Sleep(time.Hour) + } + + // Ensure valid interface and IPv4 address + +} \ No newline at end of file