Proxying implementation finished

This commit is contained in:
Kioubit 2021-12-21 06:00:28 -05:00
parent 711400607d
commit b7ca59b1bd
5 changed files with 111 additions and 43 deletions

View File

@ -9,8 +9,10 @@ const (
type NDRequest struct { type NDRequest struct {
requestType NDPType requestType NDPType
//TODO use global unicast for router advertisements
srcIP []byte srcIP []byte
answeringForIP []byte answeringForIP []byte
dstIP []byte
mac []byte mac []byte
receivedIfaceMac []byte
sourceIface string
} }

22
main.go
View File

@ -3,6 +3,8 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"os/signal"
"syscall"
) )
func main() { func main() {
@ -27,8 +29,14 @@ func simpleRespond(iface string) {
defer close(requests) defer close(requests)
go respond(iface, requests, NDP_ADV) go respond(iface, requests, NDP_ADV)
go listen(iface, requests, NDP_SOL) 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) { func proxy(iface1, iface2 string) {
@ -52,7 +60,11 @@ func proxy(iface1, iface2 string) {
go listen(iface2, req_iface2_adv_iface1, NDP_ADV) go listen(iface2, req_iface2_adv_iface1, NDP_ADV)
go respond(iface1, req_iface2_adv_iface1, NDP_ADV) go respond(iface1, req_iface2_adv_iface1, NDP_ADV)
select {} sigCh := make(chan os.Signal)
// TODO os.signal signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
select {
case <-sigCh:
fmt.Println("Exit")
os.Exit(0)
}
} }

View File

@ -2,6 +2,9 @@ package main
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"net"
"strings"
) )
var emptyIpv6 = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 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 payload []byte
} }
func newIpv6Header(srcIp []byte, dstIp []byte) *IPv6Header { func newIpv6Header(srcIp []byte, dstIp []byte) (*IPv6Header, error) {
return &IPv6Header{dstIP: dstIp, srcIP: srcIp, protocol: 0x3a} 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) { func (h *IPv6Header) addPayload(payload Payload) {
@ -61,23 +67,29 @@ type NdpPayload struct {
mac []byte 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{ return &NdpPayload{
packetType: packetType, packetType: packetType,
answeringForIP: answeringForIP, answeringForIP: answeringForIP,
mac: mac, mac: mac,
} }, nil
} }
func (p *NdpPayload) constructPacket() ([]byte, int) { func (p *NdpPayload) constructPacket() ([]byte, int) {
var protocol byte var protocol byte
var flags byte var flags byte
var linkType byte
if p.packetType == NDP_SOL { if p.packetType == NDP_SOL {
protocol = 0x87 protocol = 0x87
flags = 0x0 flags = 0x0
linkType = 0x01
} else { } else {
protocol = 0x88 protocol = 0x88
flags = 0x60 flags = 0x60
linkType = 0x02
} }
header := []byte{ header := []byte{
protocol, // Type: NDPType protocol, // Type: NDPType
@ -89,13 +101,10 @@ func (p *NdpPayload) constructPacket() ([]byte, int) {
0x0, // Reserved 0x0, // Reserved
0x0, // Reserved 0x0, // Reserved
} }
if len(p.answeringForIP) != 16 {
panic("malformed IP")
} //TODO check IP lengths on assign everywhere
final := append(header, p.answeringForIP...) final := append(header, p.answeringForIP...)
secondHeader := []byte{ secondHeader := []byte{
0x02, // Type: Target link-layer address (2) linkType, // Type
0x01, // Length: 1 (8 bytes) 0x01, // Length: 1 (8 bytes)
} }
final = append(final, secondHeader...) final = append(final, secondHeader...)
@ -123,3 +132,8 @@ func checksumAddition(b []byte) uint32 {
} }
return sum return sum
} }
func IsIPv6(ip string) bool {
rip := net.ParseIP(ip)
return rip != nil && strings.Contains(ip, ":")
}

View File

@ -50,7 +50,6 @@ func listen(iface string, responder chan *NDRequest, requestType NDPType) {
Protocol: htons16(syscall.ETH_P_IPV6), Protocol: htons16(syscall.ETH_P_IPV6),
Ifindex: niface.Index, Ifindex: niface.Index,
} }
fmt.Println(niface.HardwareAddr)
fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, htons(syscall.ETH_P_IPV6)) fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, htons(syscall.ETH_P_IPV6))
if err != nil { if err != nil {
@ -65,7 +64,7 @@ func listen(iface string, responder chan *NDRequest, requestType NDPType) {
err = syscall.Bind(fd, tiface) err = syscall.Bind(fd, tiface)
if err != nil { if err != nil {
fmt.Println(err.Error()) panic(err.Error())
} }
var f Filter var f Filter
@ -83,7 +82,7 @@ func listen(iface string, responder chan *NDRequest, requestType NDPType) {
bpf.LoadAbsolute{Off: 54, Size: 1}, bpf.LoadAbsolute{Off: 54, Size: 1},
// Jump to the drop packet instruction if Type is not Neighbor Solicitation. // Jump to the drop packet instruction if Type is not Neighbor Solicitation.
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x87, SkipTrue: 1}, 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}, bpf.RetConstant{Val: 4096},
// Verdict is "ignore packet." // Verdict is "ignore packet."
bpf.RetConstant{Val: 0}, bpf.RetConstant{Val: 0},
@ -122,6 +121,8 @@ func listen(iface string, responder chan *NDRequest, requestType NDPType) {
} }
fmt.Println("Source IP:") fmt.Println("Source IP:")
fmt.Printf("% X\n", buf[:numRead][22:38]) 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.Println("Requested IP:")
fmt.Printf("% X\n", buf[:numRead][62:78]) fmt.Printf("% X\n", buf[:numRead][62:78])
fmt.Println("Source MAC") fmt.Println("Source MAC")
@ -130,8 +131,11 @@ func listen(iface string, responder chan *NDRequest, requestType NDPType) {
responder <- &NDRequest{ responder <- &NDRequest{
requestType: requestType, requestType: requestType,
srcIP: buf[:numRead][22:38], srcIP: buf[:numRead][22:38],
dstIP: buf[:numRead][38:54],
answeringForIP: buf[:numRead][62:78], answeringForIP: buf[:numRead][62:78],
mac: buf[:numRead][80:86], mac: buf[:numRead][80:86],
receivedIfaceMac: niface.HardwareAddr,
sourceIface: iface,
} }
} }
} }

View File

@ -1,48 +1,84 @@
package main package main
import ( import (
"bytes"
"fmt"
"net" "net"
"syscall" "syscall"
) )
var fd int var globalFd int
func respond(iface string, requests chan *NDRequest, respondType NDPType) { func respond(iface string, requests chan *NDRequest, respondType NDPType) {
fd, _ = syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_RAW) fd, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
syscall.BindToDevice(fd, iface) 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) niface, err := net.InterfaceByName(iface)
if err != nil { if err != nil {
panic(err.Error()) 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 { for {
n := <-requests 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) { func pkt(ownIP []byte, dstIP []byte, tgtip []byte, mac []byte, respondType NDPType) {
v6 := newIpv6Header(emptyIpv6, srcip) v6, err := newIpv6Header(ownIP, dstIP)
NDPa := newNdpPacket(tgtip, mac, respondType) if err != nil {
return
}
NDPa, err := newNdpPacket(tgtip, mac, respondType)
if err != nil {
return
}
v6.addPayload(NDPa) v6.addPayload(NDPa)
response := v6.constructPacket() response := v6.constructPacket()
var t [16]byte var t [16]byte
if respondType == NDP_SOL { copy(t[:], dstIP)
copy(t[:], []byte{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02})
} else {
copy(t[:], srcip)
}
d := syscall.SockaddrInet6{ d := syscall.SockaddrInet6{
Port: 0, Port: 0,
Addr: t, Addr: t,
} }
err := syscall.Sendto(fd, response, 0, &d) fmt.Println("Sending packet of type", respondType, "to")
if err != nil { fmt.Printf("% X\n", t)
panic(err)
}
syscall.Close(fd) err = syscall.Sendto(globalFd, response, 0, &d)
fmt.Println(err.Error())
} }