Pndpd/pndp/responder.go

245 lines
5.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-21 06:00:28 -05:00
"bytes"
"fmt"
2021-12-20 16:46:26 -05:00
"net"
"sync"
2021-12-20 14:53:42 -05:00
"syscall"
)
2021-12-24 16:43:49 -05:00
func respond(iface string, requests chan *ndpRequest, respondType ndpType, ndpQuestionChan chan *ndpQuestion, filter []*net.IPNet, autoSense string, stopWG *sync.WaitGroup, stopChan chan struct{}) {
2021-12-25 08:21:07 -05:00
var ndpQuestionsList = make([]*ndpQuestion, 0, 40)
stopWG.Add(1)
defer stopWG.Done()
2021-12-21 06:00:28 -05:00
fd, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
if err != nil {
panic(err)
}
2021-12-25 08:21:07 -05:00
defer func(fd int) {
_ = syscall.Close(fd)
}(fd)
2021-12-21 06:00:28 -05:00
err = syscall.BindToDevice(fd, iface)
if err != nil {
panic(err)
}
2021-12-20 14:53:42 -05:00
2021-12-25 08:21:07 -05:00
nIface, err := net.InterfaceByName(iface)
2021-12-20 16:46:26 -05:00
if err != nil {
panic(err.Error())
}
2021-12-21 06:00:28 -05:00
var result = emptyIpv6
2021-12-25 08:21:07 -05:00
ifaceaddrs, err := nIface.Addrs()
2021-12-21 06:00:28 -05:00
for _, n := range ifaceaddrs {
tip, _, err := net.ParseCIDR(n.String())
if err != nil {
break
}
2021-12-25 08:21:07 -05:00
var haveUla = false
2021-12-22 07:01:30 -05:00
if isIpv6(tip.String()) {
2021-12-21 06:00:28 -05:00
if tip.IsGlobalUnicast() {
2021-12-25 08:21:07 -05:00
haveUla = true
2021-12-21 06:00:28 -05:00
result = tip
_, tnet, _ := net.ParseCIDR("fc00::/7")
if !tnet.Contains(tip) {
break
}
2021-12-25 08:21:07 -05:00
} else if tip.IsLinkLocalUnicast() && !haveUla {
result = tip
2021-12-21 06:00:28 -05:00
}
}
}
2021-12-20 14:53:42 -05:00
for {
2021-12-22 07:01:30 -05:00
var n *ndpRequest
2021-12-25 08:21:07 -05:00
if (ndpQuestionChan == nil && respondType == ndp_ADV) || (ndpQuestionChan != nil && respondType == ndp_SOL) {
2021-12-24 16:43:49 -05:00
select {
case <-stopChan:
return
case n = <-requests:
}
} else {
2021-12-25 08:21:07 -05:00
// THis is if ndpQuestionChan != nil && respondType == ndp_ADV
2021-12-24 16:43:49 -05:00
select {
case <-stopChan:
return
case q := <-ndpQuestionChan:
ndpQuestionsList = append(ndpQuestionsList, q)
2021-12-25 08:21:07 -05:00
ndpQuestionsList = cleanupQuestionList(ndpQuestionsList)
2021-12-24 16:43:49 -05:00
continue
case n = <-requests:
}
2021-12-22 06:04:00 -05:00
}
2021-12-25 08:21:07 -05:00
var _, LinkLocalSpace, _ = net.ParseCIDR("fe80::/10")
if LinkLocalSpace.Contains(n.answeringForIP) {
if GlobalDebug {
fmt.Println("Dropping packet asking for a link-local IP")
}
continue
}
if n.requestType == ndp_ADV {
if (n.rawPacket[78] != 0x02) || (n.rawPacket[79] != 0x01) {
if GlobalDebug {
fmt.Println("Dropping Advertisement packet without target Source address set")
}
continue
}
if n.rawPacket[58] == 0x0 {
if GlobalDebug {
fmt.Println("Dropping Advertisement packet without any NDP flags set")
}
continue
}
} else {
if (n.rawPacket[78] != 0x01) || (n.rawPacket[79] != 0x01) {
if GlobalDebug {
fmt.Println("Dropping Solicitation packet without Source address set")
}
continue
}
}
if !checkPacketChecksum(n.srcIP, n.dstIP, n.rawPacket[54:]) {
if GlobalDebug {
fmt.Println("Dropping packet because of invalid checksum")
}
continue
}
if autoSense != "" {
autoiface, err := net.InterfaceByName(autoSense)
if err != nil {
panic(err)
}
autoifaceaddrs, err := autoiface.Addrs()
2021-12-25 08:21:07 -05:00
for _, l := range autoifaceaddrs {
_, anet, err := net.ParseCIDR(l.String())
if err != nil {
break
}
if isIpv6(anet.String()) {
filter = append(filter, anet)
}
}
}
2021-12-21 06:14:56 -05:00
if filter != nil {
ok := false
for _, i := range filter {
if i.Contains(n.answeringForIP) {
if GlobalDebug {
fmt.Println("Responded for whitelisted IP", n.answeringForIP)
}
2021-12-21 06:14:56 -05:00
ok = true
break
}
}
if !ok {
continue
}
}
2021-12-24 13:02:57 -05:00
if GlobalDebug {
fmt.Println("Getting ready to send packet of type", respondType, "out on interface", iface)
}
2021-12-21 06:00:28 -05:00
if n.sourceIface == iface {
2021-12-25 08:21:07 -05:00
pkt(fd, result, n.srcIP, n.answeringForIP, nIface.HardwareAddr, respondType)
2021-12-21 06:00:28 -05:00
} else {
2021-12-24 16:43:49 -05:00
if respondType == ndp_ADV {
success := false
n.dstIP, success = getAddressFromQuestionListRetry(n.answeringForIP, ndpQuestionChan, ndpQuestionsList)
if !success {
if GlobalDebug {
fmt.Println("Nobody has asked for this IP")
}
continue
}
} else {
ndpQuestionChan <- &ndpQuestion{
targetIP: n.answeringForIP,
askedBy: n.srcIP,
}
2021-12-21 06:00:28 -05:00
}
2021-12-25 08:21:07 -05:00
pkt(fd, result, n.dstIP, n.answeringForIP, nIface.HardwareAddr, respondType)
2021-12-21 06:00:28 -05:00
}
2021-12-20 14:53:42 -05:00
}
}
func pkt(fd int, ownIP []byte, dstIP []byte, tgtip []byte, mac []byte, respondType ndpType) {
2021-12-21 06:00:28 -05:00
v6, err := newIpv6Header(ownIP, dstIP)
if err != nil {
return
}
NDPa, err := newNdpPacket(tgtip, mac, respondType)
if err != nil {
return
}
2021-12-20 14:53:42 -05:00
v6.addPayload(NDPa)
response := v6.constructPacket()
var t [16]byte
2021-12-21 06:00:28 -05:00
copy(t[:], dstIP)
2021-12-20 16:46:26 -05:00
2021-12-20 14:53:42 -05:00
d := syscall.SockaddrInet6{
Port: 0,
Addr: t,
}
2021-12-21 06:42:30 -05:00
if GlobalDebug {
fmt.Println("Sending packet of type", respondType, "to")
fmt.Printf("% X\n", t)
}
err = syscall.Sendto(fd, response, 0, &d)
2021-12-21 06:14:56 -05:00
if err != nil {
fmt.Println(err.Error())
}
2021-12-20 14:53:42 -05:00
}
2021-12-24 16:43:49 -05:00
func getAddressFromQuestionListRetry(targetIP []byte, ndpQuestionChan chan *ndpQuestion, ndpQuestionsList []*ndpQuestion) ([]byte, bool) {
success := false
var result []byte
result, success = getAddressFromQuestionList(targetIP, ndpQuestionsList)
if success {
return result, true
}
2021-12-24 16:58:44 -05:00
forloop:
for {
select {
case q := <-ndpQuestionChan:
ndpQuestionsList = append(ndpQuestionsList, q)
default:
break forloop
}
2021-12-24 16:43:49 -05:00
}
2021-12-24 16:58:44 -05:00
2021-12-24 16:43:49 -05:00
result, success = getAddressFromQuestionList(targetIP, ndpQuestionsList)
return result, success
}
func getAddressFromQuestionList(targetIP []byte, ndpQuestionsList []*ndpQuestion) ([]byte, bool) {
2021-12-25 08:21:07 -05:00
for i := range ndpQuestionsList {
2021-12-24 16:43:49 -05:00
if bytes.Equal((*ndpQuestionsList[i]).targetIP, targetIP) {
result := (*ndpQuestionsList[i]).askedBy
ndpQuestionsList = removeFromQuestionList(ndpQuestionsList, i)
return result, true
}
}
return nil, false
}
func removeFromQuestionList(s []*ndpQuestion, i int) []*ndpQuestion {
s[i] = s[len(s)-1]
return s[:len(s)-1]
}
2021-12-25 08:21:07 -05:00
func cleanupQuestionList(s []*ndpQuestion) []*ndpQuestion {
for len(s) >= 40 {
s = removeFromQuestionList(s, 0)
}
return s
}