Small code optimizations
This commit is contained in:
parent
5a901eada3
commit
0f580cbbbd
@ -12,8 +12,6 @@ type ndpRequest struct {
|
|||||||
srcIP []byte
|
srcIP []byte
|
||||||
answeringForIP []byte
|
answeringForIP []byte
|
||||||
dstIP []byte
|
dstIP []byte
|
||||||
mac []byte
|
|
||||||
receivedIfaceMac []byte
|
|
||||||
sourceIface string
|
sourceIface string
|
||||||
rawPacket []byte
|
rawPacket []byte
|
||||||
}
|
}
|
||||||
|
58
pndp/interface.go
Normal file
58
pndp/interface.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package pndp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/net/bpf"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// bpfFilter represents a classic BPF filter program that can be applied to a socket
|
||||||
|
type bpfFilter []bpf.Instruction
|
||||||
|
|
||||||
|
// ApplyTo applies the current filter onto the provided file descriptor
|
||||||
|
func (filter bpfFilter) ApplyTo(fd int) (err error) {
|
||||||
|
var assembled []bpf.RawInstruction
|
||||||
|
if assembled, err = bpf.Assemble(filter); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var program = unix.SockFprog{
|
||||||
|
Len: uint16(len(assembled)),
|
||||||
|
Filter: (*unix.SockFilter)(unsafe.Pointer(&assembled[0])),
|
||||||
|
}
|
||||||
|
var b = (*[unix.SizeofSockFprog]byte)(unsafe.Pointer(&program))[:unix.SizeofSockFprog]
|
||||||
|
|
||||||
|
if _, _, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT,
|
||||||
|
uintptr(fd), uintptr(syscall.SOL_SOCKET), uintptr(syscall.SO_ATTACH_FILTER),
|
||||||
|
uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), 0); errno != 0 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type iflags struct {
|
||||||
|
name [syscall.IFNAMSIZ]byte
|
||||||
|
flags uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func setAllMulti(fd int, iface string, enable bool) {
|
||||||
|
var ifl iflags
|
||||||
|
copy(ifl.name[:], []byte(iface))
|
||||||
|
_, _, ep := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
|
||||||
|
if ep != 0 {
|
||||||
|
panic(ep)
|
||||||
|
}
|
||||||
|
|
||||||
|
if enable {
|
||||||
|
ifl.flags |= uint16(syscall.IFF_ALLMULTI)
|
||||||
|
} else {
|
||||||
|
ifl.flags &^= uint16(syscall.IFF_ALLMULTI)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, ep = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
|
||||||
|
if ep != 0 {
|
||||||
|
panic(ep)
|
||||||
|
}
|
||||||
|
}
|
@ -4,38 +4,11 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"golang.org/x/net/bpf"
|
"golang.org/x/net/bpf"
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// bpfFilter represents a classic BPF filter program that can be applied to a socket
|
|
||||||
type bpfFilter []bpf.Instruction
|
|
||||||
|
|
||||||
// ApplyTo applies the current filter onto the provided file descriptor
|
|
||||||
func (filter bpfFilter) ApplyTo(fd int) (err error) {
|
|
||||||
var assembled []bpf.RawInstruction
|
|
||||||
if assembled, err = bpf.Assemble(filter); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var program = unix.SockFprog{
|
|
||||||
Len: uint16(len(assembled)),
|
|
||||||
Filter: (*unix.SockFilter)(unsafe.Pointer(&assembled[0])),
|
|
||||||
}
|
|
||||||
var b = (*[unix.SizeofSockFprog]byte)(unsafe.Pointer(&program))[:unix.SizeofSockFprog]
|
|
||||||
|
|
||||||
if _, _, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT,
|
|
||||||
uintptr(fd), uintptr(syscall.SOL_SOCKET), uintptr(syscall.SO_ATTACH_FILTER),
|
|
||||||
uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), 0); errno != 0 {
|
|
||||||
return errno
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Htons Convert a uint16 to host byte order (big endian)
|
// Htons Convert a uint16 to host byte order (big endian)
|
||||||
func htons(v uint16) int {
|
func htons(v uint16) int {
|
||||||
return int((v << 8) | (v >> 8))
|
return int((v << 8) | (v >> 8))
|
||||||
@ -159,35 +132,8 @@ func listen(iface string, responder chan *ndpRequest, requestType ndpType, stopW
|
|||||||
srcIP: buf[22:38],
|
srcIP: buf[22:38],
|
||||||
dstIP: buf[38:54],
|
dstIP: buf[38:54],
|
||||||
answeringForIP: buf[62:78],
|
answeringForIP: buf[62:78],
|
||||||
mac: buf[80:86],
|
|
||||||
receivedIfaceMac: niface.HardwareAddr,
|
|
||||||
sourceIface: iface,
|
sourceIface: iface,
|
||||||
rawPacket: buf[:numRead],
|
rawPacket: buf[:numRead],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type iflags struct {
|
|
||||||
name [syscall.IFNAMSIZ]byte
|
|
||||||
flags uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
func setAllMulti(fd int, iface string, enable bool) {
|
|
||||||
var ifl iflags
|
|
||||||
copy(ifl.name[:], []byte(iface))
|
|
||||||
_, _, ep := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
|
|
||||||
if ep != 0 {
|
|
||||||
panic(ep)
|
|
||||||
}
|
|
||||||
|
|
||||||
if enable {
|
|
||||||
ifl.flags |= uint16(syscall.IFF_ALLMULTI)
|
|
||||||
} else {
|
|
||||||
ifl.flags &^= uint16(syscall.IFF_ALLMULTI)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _, ep = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
|
|
||||||
if ep != 0 {
|
|
||||||
panic(ep)
|
|
||||||
}
|
|
||||||
}
|
|
@ -144,12 +144,7 @@ func checksumAddition(b []byte) uint32 {
|
|||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkPacketChecksum(scrip, dstip, payload []byte) bool {
|
func checkPacketChecksum(v6 *ipv6Header, payload []byte) bool {
|
||||||
v6, err := newIpv6Header(scrip, dstip)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
packetsum := make([]byte, 2)
|
packetsum := make([]byte, 2)
|
||||||
copy(packetsum, payload[2:4])
|
copy(packetsum, payload[2:4])
|
||||||
|
|
||||||
@ -163,9 +158,6 @@ func checkPacketChecksum(scrip, dstip, payload []byte) bool {
|
|||||||
bChecksum := make([]byte, 2)
|
bChecksum := make([]byte, 2)
|
||||||
binary.BigEndian.PutUint16(bChecksum, calculateChecksum(v6, payload))
|
binary.BigEndian.PutUint16(bChecksum, calculateChecksum(v6, payload))
|
||||||
if bytes.Equal(packetsum, bChecksum) {
|
if bytes.Equal(packetsum, bChecksum) {
|
||||||
if GlobalDebug {
|
|
||||||
fmt.Println("Verified received packet checksum")
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
if GlobalDebug {
|
if GlobalDebug {
|
||||||
|
@ -35,7 +35,9 @@ type ProxyObj struct {
|
|||||||
// With the optional autosenseInterface argument, the whitelist is configured based on the addresses assigned to the interface specified. This works even if the IP addresses change frequently.
|
// With the optional autosenseInterface argument, the whitelist is configured based on the addresses assigned to the interface specified. This works even if the IP addresses change frequently.
|
||||||
// Start() must be called on the object to actually start responding
|
// Start() must be called on the object to actually start responding
|
||||||
func NewResponder(iface string, filter []*net.IPNet, autosenseInterface string) *ResponderObj {
|
func NewResponder(iface string, filter []*net.IPNet, autosenseInterface string) *ResponderObj {
|
||||||
|
if filter == nil {
|
||||||
fmt.Println("WARNING: You should use a whitelist for the responder unless you really know what you are doing")
|
fmt.Println("WARNING: You should use a whitelist for the responder unless you really know what you are doing")
|
||||||
|
}
|
||||||
var s sync.WaitGroup
|
var s sync.WaitGroup
|
||||||
return &ResponderObj{
|
return &ResponderObj{
|
||||||
stopChan: make(chan struct{}),
|
stopChan: make(chan struct{}),
|
||||||
@ -146,7 +148,7 @@ func (obj *ProxyObj) Stop() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseFilter Helper Function to Parse a string of CIDRs separated by a semicolon as a Whitelist for SimpleRespond
|
// ParseFilter Helper Function to Parse a string of CIDRs separated by a semicolon as a Whitelist
|
||||||
func ParseFilter(f string) []*net.IPNet {
|
func ParseFilter(f string) []*net.IPNet {
|
||||||
if f == "" {
|
if f == "" {
|
||||||
return nil
|
return nil
|
||||||
|
@ -9,9 +9,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func respond(iface string, requests chan *ndpRequest, respondType ndpType, ndpQuestionChan chan *ndpQuestion, filter []*net.IPNet, autoSense string, stopWG *sync.WaitGroup, stopChan chan struct{}) {
|
func respond(iface string, requests chan *ndpRequest, respondType ndpType, ndpQuestionChan chan *ndpQuestion, filter []*net.IPNet, autoSense string, stopWG *sync.WaitGroup, stopChan chan struct{}) {
|
||||||
var ndpQuestionsList = make([]*ndpQuestion, 0, 40)
|
|
||||||
stopWG.Add(1)
|
stopWG.Add(1)
|
||||||
defer stopWG.Done()
|
defer stopWG.Done()
|
||||||
|
|
||||||
|
var ndpQuestionsList = make([]*ndpQuestion, 0, 40)
|
||||||
|
var _, linkLocalSpace, _ = net.ParseCIDR("fe80::/10")
|
||||||
|
var _, ulaSpace, _ = net.ParseCIDR("fc00::/7")
|
||||||
|
|
||||||
fd, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
|
fd, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -24,13 +28,13 @@ func respond(iface string, requests chan *ndpRequest, respondType ndpType, ndpQu
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nIface, err := net.InterfaceByName(iface)
|
respondIface, err := net.InterfaceByName(iface)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = emptyIpv6
|
var result = emptyIpv6
|
||||||
ifaceaddrs, err := nIface.Addrs()
|
ifaceaddrs, err := respondIface.Addrs()
|
||||||
|
|
||||||
for _, n := range ifaceaddrs {
|
for _, n := range ifaceaddrs {
|
||||||
tip, _, err := net.ParseCIDR(n.String())
|
tip, _, err := net.ParseCIDR(n.String())
|
||||||
@ -42,8 +46,8 @@ func respond(iface string, requests chan *ndpRequest, respondType ndpType, ndpQu
|
|||||||
if tip.IsGlobalUnicast() {
|
if tip.IsGlobalUnicast() {
|
||||||
haveUla = true
|
haveUla = true
|
||||||
result = tip
|
result = tip
|
||||||
_, tnet, _ := net.ParseCIDR("fc00::/7")
|
|
||||||
if !tnet.Contains(tip) {
|
if !ulaSpace.Contains(tip) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else if tip.IsLinkLocalUnicast() && !haveUla {
|
} else if tip.IsLinkLocalUnicast() && !haveUla {
|
||||||
@ -53,15 +57,15 @@ func respond(iface string, requests chan *ndpRequest, respondType ndpType, ndpQu
|
|||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var n *ndpRequest
|
var req *ndpRequest
|
||||||
if (ndpQuestionChan == nil && respondType == ndp_ADV) || (ndpQuestionChan != nil && respondType == ndp_SOL) {
|
if (ndpQuestionChan == nil && respondType == ndp_ADV) || (ndpQuestionChan != nil && respondType == ndp_SOL) {
|
||||||
select {
|
select {
|
||||||
case <-stopChan:
|
case <-stopChan:
|
||||||
return
|
return
|
||||||
case n = <-requests:
|
case req = <-requests:
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// THis is if ndpQuestionChan != nil && respondType == ndp_ADV
|
// This is if ndpQuestionChan != nil && respondType == ndp_ADV
|
||||||
select {
|
select {
|
||||||
case <-stopChan:
|
case <-stopChan:
|
||||||
return
|
return
|
||||||
@ -69,33 +73,32 @@ func respond(iface string, requests chan *ndpRequest, respondType ndpType, ndpQu
|
|||||||
ndpQuestionsList = append(ndpQuestionsList, q)
|
ndpQuestionsList = append(ndpQuestionsList, q)
|
||||||
ndpQuestionsList = cleanupQuestionList(ndpQuestionsList)
|
ndpQuestionsList = cleanupQuestionList(ndpQuestionsList)
|
||||||
continue
|
continue
|
||||||
case n = <-requests:
|
case req = <-requests:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _, LinkLocalSpace, _ = net.ParseCIDR("fe80::/10")
|
if linkLocalSpace.Contains(req.answeringForIP) {
|
||||||
if LinkLocalSpace.Contains(n.answeringForIP) {
|
|
||||||
if GlobalDebug {
|
if GlobalDebug {
|
||||||
fmt.Println("Dropping packet asking for a link-local IP")
|
fmt.Println("Dropping packet asking for a link-local IP")
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.requestType == ndp_ADV {
|
if req.requestType == ndp_ADV {
|
||||||
if (n.rawPacket[78] != 0x02) || (n.rawPacket[79] != 0x01) {
|
if (req.rawPacket[78] != 0x02) || (req.rawPacket[79] != 0x01) {
|
||||||
if GlobalDebug {
|
if GlobalDebug {
|
||||||
fmt.Println("Dropping Advertisement packet without target Source address set")
|
fmt.Println("Dropping Advertisement packet without target Source address set")
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n.rawPacket[58] == 0x0 {
|
if req.rawPacket[58] == 0x0 {
|
||||||
if GlobalDebug {
|
if GlobalDebug {
|
||||||
fmt.Println("Dropping Advertisement packet without any NDP flags set")
|
fmt.Println("Dropping Advertisement packet without any NDP flags set")
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (n.rawPacket[78] != 0x01) || (n.rawPacket[79] != 0x01) {
|
if (req.rawPacket[78] != 0x01) || (req.rawPacket[79] != 0x01) {
|
||||||
if GlobalDebug {
|
if GlobalDebug {
|
||||||
fmt.Println("Dropping Solicitation packet without Source address set")
|
fmt.Println("Dropping Solicitation packet without Source address set")
|
||||||
}
|
}
|
||||||
@ -103,7 +106,11 @@ func respond(iface string, requests chan *ndpRequest, respondType ndpType, ndpQu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !checkPacketChecksum(n.srcIP, n.dstIP, n.rawPacket[54:]) {
|
v6Header, err := newIpv6Header(req.srcIP, req.dstIP)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !checkPacketChecksum(v6Header, req.rawPacket[54:]) {
|
||||||
if GlobalDebug {
|
if GlobalDebug {
|
||||||
fmt.Println("Dropping packet because of invalid checksum")
|
fmt.Println("Dropping packet because of invalid checksum")
|
||||||
}
|
}
|
||||||
@ -131,9 +138,9 @@ func respond(iface string, requests chan *ndpRequest, respondType ndpType, ndpQu
|
|||||||
if filter != nil {
|
if filter != nil {
|
||||||
ok := false
|
ok := false
|
||||||
for _, i := range filter {
|
for _, i := range filter {
|
||||||
if i.Contains(n.answeringForIP) {
|
if i.Contains(req.answeringForIP) {
|
||||||
if GlobalDebug {
|
if GlobalDebug {
|
||||||
fmt.Println("Responded for whitelisted IP", n.answeringForIP)
|
fmt.Println("Responded for whitelisted IP", req.answeringForIP)
|
||||||
}
|
}
|
||||||
ok = true
|
ok = true
|
||||||
break
|
break
|
||||||
@ -148,12 +155,12 @@ func respond(iface string, requests chan *ndpRequest, respondType ndpType, ndpQu
|
|||||||
fmt.Println("Getting ready to send packet of type", respondType, "out on interface", iface)
|
fmt.Println("Getting ready to send packet of type", respondType, "out on interface", iface)
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.sourceIface == iface {
|
if req.sourceIface == iface {
|
||||||
pkt(fd, result, n.srcIP, n.answeringForIP, nIface.HardwareAddr, respondType)
|
pkt(fd, result, req.srcIP, req.answeringForIP, respondIface.HardwareAddr, respondType)
|
||||||
} else {
|
} else {
|
||||||
if respondType == ndp_ADV {
|
if respondType == ndp_ADV {
|
||||||
success := false
|
success := false
|
||||||
n.dstIP, success = getAddressFromQuestionListRetry(n.answeringForIP, ndpQuestionChan, ndpQuestionsList)
|
req.dstIP, success = getAddressFromQuestionListRetry(req.answeringForIP, ndpQuestionChan, ndpQuestionsList)
|
||||||
if !success {
|
if !success {
|
||||||
if GlobalDebug {
|
if GlobalDebug {
|
||||||
fmt.Println("Nobody has asked for this IP")
|
fmt.Println("Nobody has asked for this IP")
|
||||||
@ -162,11 +169,11 @@ func respond(iface string, requests chan *ndpRequest, respondType ndpType, ndpQu
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ndpQuestionChan <- &ndpQuestion{
|
ndpQuestionChan <- &ndpQuestion{
|
||||||
targetIP: n.answeringForIP,
|
targetIP: req.answeringForIP,
|
||||||
askedBy: n.srcIP,
|
askedBy: req.srcIP,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pkt(fd, result, n.dstIP, n.answeringForIP, nIface.HardwareAddr, respondType)
|
pkt(fd, result, req.dstIP, req.answeringForIP, respondIface.HardwareAddr, respondType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,17 +214,23 @@ func getAddressFromQuestionListRetry(targetIP []byte, ndpQuestionChan chan *ndpQ
|
|||||||
if success {
|
if success {
|
||||||
return result, true
|
return result, true
|
||||||
}
|
}
|
||||||
forloop:
|
|
||||||
for {
|
hasBuffered := true
|
||||||
|
gotBuffered := false
|
||||||
|
for hasBuffered {
|
||||||
select {
|
select {
|
||||||
case q := <-ndpQuestionChan:
|
case q := <-ndpQuestionChan:
|
||||||
ndpQuestionsList = append(ndpQuestionsList, q)
|
ndpQuestionsList = append(ndpQuestionsList, q)
|
||||||
|
gotBuffered = true
|
||||||
default:
|
default:
|
||||||
break forloop
|
hasBuffered = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if gotBuffered {
|
||||||
result, success = getAddressFromQuestionList(targetIP, ndpQuestionsList)
|
result, success = getAddressFromQuestionList(targetIP, ndpQuestionsList)
|
||||||
|
}
|
||||||
|
|
||||||
return result, success
|
return result, success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user