Pndpd/pndp/listener.go

147 lines
3.6 KiB
Go
Raw Normal View History

2021-12-22 07:01:30 -05:00
package pndp
2021-12-20 14:53:42 -05:00
import (
2021-12-24 16:43:49 -05:00
"bytes"
2021-12-20 14:53:42 -05:00
"fmt"
"golang.org/x/net/bpf"
"net"
"sync"
2021-12-20 14:53:42 -05:00
"syscall"
)
// Htons Convert a uint16 to host byte order (big endian)
func htons(v uint16) int {
return int((v << 8) | (v >> 8))
}
func htons16(v uint16) uint16 { return v<<8 | v>>8 }
func listen(iface string, responder chan *ndpRequest, requestType ndpType, stopWG *sync.WaitGroup, stopChan chan struct{}) {
stopWG.Add(1)
defer stopWG.Done()
2021-12-25 08:21:07 -05:00
2021-12-20 14:53:42 -05:00
niface, err := net.InterfaceByName(iface)
if err != nil {
panic(err.Error())
}
tiface := &syscall.SockaddrLinklayer{
Protocol: htons16(syscall.ETH_P_IPV6),
Ifindex: niface.Index,
}
fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, htons(syscall.ETH_P_IPV6))
if err != nil {
fmt.Println(err.Error())
}
2021-12-22 06:04:00 -05:00
go func() {
<-stopChan
setPromisc(fd, iface, false, false)
2021-12-25 08:21:07 -05:00
_ = syscall.Close(fd)
stopWG.Done() // syscall.read does not release when the file descriptor is closed
2021-12-22 06:04:00 -05:00
}()
2021-12-24 13:02:57 -05:00
if GlobalDebug {
fmt.Println("Obtained fd ", fd)
}
2021-12-20 14:53:42 -05:00
if len([]byte(iface)) > syscall.IFNAMSIZ {
panic("Interface size larger then maximum allowed by the kernel")
}
err = syscall.Bind(fd, tiface)
if err != nil {
2021-12-21 06:00:28 -05:00
panic(err.Error())
2021-12-20 14:53:42 -05:00
}
setPromisc(fd, iface, true, false)
2021-12-26 07:13:48 -05:00
2021-12-22 06:09:52 -05:00
var protocolNo uint32
2021-12-22 07:01:30 -05:00
if requestType == ndp_SOL {
2021-12-22 06:09:52 -05:00
//Neighbor Solicitation
protocolNo = 0x87
2021-12-20 16:46:26 -05:00
} else {
2021-12-22 06:09:52 -05:00
//Neighbor Advertisement
protocolNo = 0x88
}
2021-12-24 18:04:09 -05:00
var f bpfFilter
f = []bpf.Instruction{
2021-12-22 06:09:52 -05:00
// Load "EtherType" field from the ethernet header.
bpf.LoadAbsolute{Off: 12, Size: 2},
// Jump to the drop packet instruction if EtherType is not IPv6.
2021-12-24 18:04:09 -05:00
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x86dd, SkipTrue: 5},
2021-12-22 06:09:52 -05:00
// Load "Next Header" field from IPV6 header.
bpf.LoadAbsolute{Off: 20, Size: 1},
// Jump to the drop packet instruction if Next Header is not ICMPv6.
2021-12-24 18:04:09 -05:00
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x3a, SkipTrue: 3},
2021-12-22 06:09:52 -05:00
// Load "Type" field from ICMPv6 header.
bpf.LoadAbsolute{Off: 54, Size: 1},
// Jump to the drop packet instruction if Type is not Neighbor Solicitation / Advertisement.
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: protocolNo, SkipTrue: 1},
// Verdict is: send up to 86 bytes of the packet to userspace.
bpf.RetConstant{Val: 86},
2021-12-25 08:21:07 -05:00
// Verdict is: "ignore packet."
2021-12-22 06:09:52 -05:00
bpf.RetConstant{Val: 0},
2021-12-20 14:53:42 -05:00
}
err = f.ApplyTo(fd)
if err != nil {
panic(err.Error())
}
for {
buf := make([]byte, 86)
2021-12-20 14:53:42 -05:00
numRead, err := syscall.Read(fd, buf)
if err != nil {
panic(err)
}
if numRead < 78 {
2021-12-24 16:43:49 -05:00
if GlobalDebug {
fmt.Println("Dropping packet since it does not meet the minimum length requirement")
fmt.Printf("% X\n", buf[:numRead])
}
continue
}
2021-12-21 06:42:30 -05:00
if GlobalDebug {
2021-12-24 13:02:57 -05:00
fmt.Println("Got packet on", iface, "of type", requestType)
2021-12-24 16:43:49 -05:00
fmt.Printf("% X\n", buf[:numRead])
2021-12-25 08:21:07 -05:00
fmt.Println("Source mac on ethernet layer:")
fmt.Printf("% X\n", buf[6:12])
2021-12-21 06:42:30 -05:00
fmt.Println("Source IP:")
2021-12-25 08:21:07 -05:00
fmt.Printf("% X\n", buf[22:38])
2021-12-21 06:42:30 -05:00
fmt.Println("Destination IP:")
2021-12-25 08:21:07 -05:00
fmt.Printf("% X\n", buf[38:54])
2021-12-21 06:42:30 -05:00
fmt.Println("Requested IP:")
2021-12-25 08:21:07 -05:00
fmt.Printf("% X\n", buf[62:78])
if requestType == ndp_ADV {
fmt.Println("NDP Flags")
fmt.Printf("% X\n", buf[58])
}
2021-12-21 06:42:30 -05:00
fmt.Println()
}
2021-12-24 16:43:49 -05:00
2021-12-25 08:21:07 -05:00
if bytes.Equal(buf[6:12], niface.HardwareAddr) {
2021-12-24 16:43:49 -05:00
if GlobalDebug {
fmt.Println("Dropping packet from ourselves")
}
continue
}
if requestType == ndp_ADV {
if buf[58] == 0x0 {
if GlobalDebug {
fmt.Println("Dropping Advertisement packet without any NDP flags set")
}
continue
}
}
2021-12-22 07:01:30 -05:00
responder <- &ndpRequest{
2021-12-27 07:58:10 -05:00
requestType: requestType,
srcIP: buf[22:38],
dstIP: buf[38:54],
answeringForIP: buf[62:78],
payload: buf[54:],
2021-12-27 07:58:10 -05:00
sourceIface: iface,
2021-12-20 14:53:42 -05:00
}
}
}