Proxying implementation finished
This commit is contained in:
parent
711400607d
commit
b7ca59b1bd
@ -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
22
main.go
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
30
packet.go
30
packet.go
@ -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, ":")
|
||||||
|
}
|
||||||
|
10
rawsocket.go
10
rawsocket.go
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
74
responder.go
74
responder.go
@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
var result = emptyIpv6
|
||||||
n := <-requests
|
ifaceaddrs, err := niface.Addrs()
|
||||||
pkt(n.srcIP, n.answeringForIP, niface.HardwareAddr, respondType)
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pkt(srcip []byte, tgtip []byte, mac []byte, respondType NDPType) {
|
for {
|
||||||
v6 := newIpv6Header(emptyIpv6, srcip)
|
n := <-requests
|
||||||
NDPa := newNdpPacket(tgtip, mac, 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(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)
|
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())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user