From b7ca59b1bdb6e8ff84fdacd8034cc02b8d433c0f Mon Sep 17 00:00:00 2001 From: Kioubit Date: Tue, 21 Dec 2021 06:00:28 -0500 Subject: [PATCH] Proxying implementation finished --- NDPRequest.go | 12 +++++---- main.go | 22 ++++++++++++---- packet.go | 32 ++++++++++++++++------- rawsocket.go | 18 +++++++------ responder.go | 70 ++++++++++++++++++++++++++++++++++++++------------- 5 files changed, 111 insertions(+), 43 deletions(-) diff --git a/NDPRequest.go b/NDPRequest.go index b646f4f..689b1fc 100644 --- a/NDPRequest.go +++ b/NDPRequest.go @@ -8,9 +8,11 @@ const ( ) type NDRequest struct { - requestType NDPType - //TODO use global unicast for router advertisements - srcIP []byte - answeringForIP []byte - mac []byte + requestType NDPType + srcIP []byte + answeringForIP []byte + dstIP []byte + mac []byte + receivedIfaceMac []byte + sourceIface string } diff --git a/main.go b/main.go index 49c0186..4b4ab39 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,8 @@ package main import ( "fmt" "os" + "os/signal" + "syscall" ) func main() { @@ -27,8 +29,14 @@ func simpleRespond(iface string) { defer close(requests) go respond(iface, requests, NDP_ADV) go listen(iface, requests, NDP_SOL) - select {} - //TODO os.signal + + sigCh := make(chan os.Signal) + signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) + select { + case <-sigCh: + fmt.Println("Exit") + os.Exit(0) + } } func proxy(iface1, iface2 string) { @@ -52,7 +60,11 @@ func proxy(iface1, iface2 string) { go listen(iface2, req_iface2_adv_iface1, NDP_ADV) go respond(iface1, req_iface2_adv_iface1, NDP_ADV) - select {} - // TODO os.signal - + sigCh := make(chan os.Signal) + signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) + select { + case <-sigCh: + fmt.Println("Exit") + os.Exit(0) + } } diff --git a/packet.go b/packet.go index 05bf817..1ba24ea 100644 --- a/packet.go +++ b/packet.go @@ -2,6 +2,9 @@ package main import ( "encoding/binary" + "errors" + "net" + "strings" ) var emptyIpv6 = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -18,8 +21,11 @@ type IPv6Header struct { payload []byte } -func newIpv6Header(srcIp []byte, dstIp []byte) *IPv6Header { - return &IPv6Header{dstIP: dstIp, srcIP: srcIp, protocol: 0x3a} +func newIpv6Header(srcIp []byte, dstIp []byte) (*IPv6Header, error) { + if len(dstIp) != 16 || len(srcIp) != 16 { + return nil, errors.New("malformed IP") + } + return &IPv6Header{dstIP: dstIp, srcIP: srcIp, protocol: 0x3a}, nil } func (h *IPv6Header) addPayload(payload Payload) { @@ -61,23 +67,29 @@ type NdpPayload struct { mac []byte } -func newNdpPacket(answeringForIP []byte, mac []byte, packetType NDPType) *NdpPayload { +func newNdpPacket(answeringForIP []byte, mac []byte, packetType NDPType) (*NdpPayload, error) { + if len(answeringForIP) != 16 || len(mac) != 6 { + return nil, errors.New("malformed IP") + } return &NdpPayload{ packetType: packetType, answeringForIP: answeringForIP, mac: mac, - } + }, nil } func (p *NdpPayload) constructPacket() ([]byte, int) { var protocol byte var flags byte + var linkType byte if p.packetType == NDP_SOL { protocol = 0x87 flags = 0x0 + linkType = 0x01 } else { protocol = 0x88 flags = 0x60 + linkType = 0x02 } header := []byte{ protocol, // Type: NDPType @@ -89,14 +101,11 @@ func (p *NdpPayload) constructPacket() ([]byte, int) { 0x0, // Reserved 0x0, // Reserved } - if len(p.answeringForIP) != 16 { - panic("malformed IP") - } //TODO check IP lengths on assign everywhere final := append(header, p.answeringForIP...) secondHeader := []byte{ - 0x02, // Type: Target link-layer address (2) - 0x01, // Length: 1 (8 bytes) + linkType, // Type + 0x01, // Length: 1 (8 bytes) } final = append(final, secondHeader...) @@ -123,3 +132,8 @@ func checksumAddition(b []byte) uint32 { } return sum } + +func IsIPv6(ip string) bool { + rip := net.ParseIP(ip) + return rip != nil && strings.Contains(ip, ":") +} diff --git a/rawsocket.go b/rawsocket.go index fa9dceb..a6e17c7 100644 --- a/rawsocket.go +++ b/rawsocket.go @@ -50,7 +50,6 @@ func listen(iface string, responder chan *NDRequest, requestType NDPType) { Protocol: htons16(syscall.ETH_P_IPV6), Ifindex: niface.Index, } - fmt.Println(niface.HardwareAddr) fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, htons(syscall.ETH_P_IPV6)) if err != nil { @@ -65,7 +64,7 @@ func listen(iface string, responder chan *NDRequest, requestType NDPType) { err = syscall.Bind(fd, tiface) if err != nil { - fmt.Println(err.Error()) + panic(err.Error()) } var f Filter @@ -83,7 +82,7 @@ func listen(iface string, responder chan *NDRequest, requestType NDPType) { bpf.LoadAbsolute{Off: 54, Size: 1}, // Jump to the drop packet instruction if Type is not Neighbor Solicitation. bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x87, SkipTrue: 1}, - // Verdict is "send up to 4k of the packet to userspace." + // Verdict is "send up to 4k of the packet to userspace."buf bpf.RetConstant{Val: 4096}, // Verdict is "ignore packet." bpf.RetConstant{Val: 0}, @@ -122,16 +121,21 @@ func listen(iface string, responder chan *NDRequest, requestType NDPType) { } fmt.Println("Source IP:") fmt.Printf("% X\n", buf[:numRead][22:38]) + fmt.Println("Destination IP:") + fmt.Printf("% X\n", buf[:numRead][38:54]) fmt.Println("Requested IP:") fmt.Printf("% X\n", buf[:numRead][62:78]) fmt.Println("Source MAC") fmt.Printf("% X\n", buf[:numRead][80:86]) fmt.Println() responder <- &NDRequest{ - requestType: requestType, - srcIP: buf[:numRead][22:38], - answeringForIP: buf[:numRead][62:78], - mac: buf[:numRead][80:86], + requestType: requestType, + srcIP: buf[:numRead][22:38], + dstIP: buf[:numRead][38:54], + answeringForIP: buf[:numRead][62:78], + mac: buf[:numRead][80:86], + receivedIfaceMac: niface.HardwareAddr, + sourceIface: iface, } } } diff --git a/responder.go b/responder.go index 6eac2a5..e462502 100644 --- a/responder.go +++ b/responder.go @@ -1,48 +1,84 @@ package main import ( + "bytes" + "fmt" "net" "syscall" ) -var fd int +var globalFd int func respond(iface string, requests chan *NDRequest, respondType NDPType) { - fd, _ = syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_RAW) - syscall.BindToDevice(fd, iface) + fd, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_RAW) + if err != nil { + panic(err) + } + defer syscall.Close(globalFd) + globalFd = fd + err = syscall.BindToDevice(fd, iface) + if err != nil { + panic(err) + } niface, err := net.InterfaceByName(iface) if err != nil { panic(err.Error()) } + var result = emptyIpv6 + ifaceaddrs, err := niface.Addrs() + + for _, n := range ifaceaddrs { + tip, _, err := net.ParseCIDR(n.String()) + if err != nil { + break + } + if IsIPv6(tip.String()) { + if tip.IsGlobalUnicast() { + result = tip + _, tnet, _ := net.ParseCIDR("fc00::/7") + if !tnet.Contains(tip) { + break + } + } + } + } + for { n := <-requests - pkt(n.srcIP, n.answeringForIP, niface.HardwareAddr, respondType) + if n.sourceIface == iface { + pkt(result, n.srcIP, n.answeringForIP, niface.HardwareAddr, respondType) + } else { + if !bytes.Equal(n.mac, n.receivedIfaceMac) { + pkt(n.srcIP, n.dstIP, n.answeringForIP, niface.HardwareAddr, respondType) + } + } } } -func pkt(srcip []byte, tgtip []byte, mac []byte, respondType NDPType) { - v6 := newIpv6Header(emptyIpv6, srcip) - NDPa := newNdpPacket(tgtip, mac, respondType) +func pkt(ownIP []byte, dstIP []byte, tgtip []byte, mac []byte, respondType NDPType) { + v6, err := newIpv6Header(ownIP, dstIP) + if err != nil { + return + } + NDPa, err := newNdpPacket(tgtip, mac, respondType) + if err != nil { + return + } v6.addPayload(NDPa) response := v6.constructPacket() var t [16]byte - if respondType == NDP_SOL { - copy(t[:], []byte{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02}) - } else { - copy(t[:], srcip) - } + copy(t[:], dstIP) d := syscall.SockaddrInet6{ Port: 0, Addr: t, } - err := syscall.Sendto(fd, response, 0, &d) - if err != nil { - panic(err) - } + fmt.Println("Sending packet of type", respondType, "to") + fmt.Printf("% X\n", t) - syscall.Close(fd) + err = syscall.Sendto(globalFd, response, 0, &d) + fmt.Println(err.Error()) }