Initial proxying implementation
This commit is contained in:
parent
18f14ba47d
commit
711400607d
@ -1,6 +1,15 @@
|
||||
package main
|
||||
|
||||
type NDPType int
|
||||
|
||||
const (
|
||||
NDP_ADV NDPType = 0
|
||||
NDP_SOL NDPType = 1
|
||||
)
|
||||
|
||||
type NDRequest struct {
|
||||
requestType NDPType
|
||||
//TODO use global unicast for router advertisements
|
||||
srcIP []byte
|
||||
answeringForIP []byte
|
||||
mac []byte
|
||||
|
51
main.go
51
main.go
@ -6,14 +6,53 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("Usage: pndpd respond <interface>")
|
||||
fmt.Println("Usage: pndpd proxy <interface1> <interface2>")
|
||||
|
||||
if len(os.Args) <= 1 {
|
||||
fmt.Println("Specify interface")
|
||||
fmt.Println("Specify command")
|
||||
os.Exit(1)
|
||||
}
|
||||
iface := os.Args[1]
|
||||
requests := make(chan *NDRequest, 100)
|
||||
defer close(requests)
|
||||
go respond(iface, requests)
|
||||
listen(iface, requests)
|
||||
if os.Args[1] == "respond" {
|
||||
simpleRespond(os.Args[2])
|
||||
}
|
||||
if os.Args[1] == "proxy" {
|
||||
proxy(os.Args[2], os.Args[3])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func simpleRespond(iface string) {
|
||||
requests := make(chan *NDRequest, 100)
|
||||
defer close(requests)
|
||||
go respond(iface, requests, NDP_ADV)
|
||||
go listen(iface, requests, NDP_SOL)
|
||||
select {}
|
||||
//TODO os.signal
|
||||
}
|
||||
|
||||
func proxy(iface1, iface2 string) {
|
||||
req_iface1_sol_iface2 := make(chan *NDRequest, 100)
|
||||
defer close(req_iface1_sol_iface2)
|
||||
go listen(iface1, req_iface1_sol_iface2, NDP_SOL)
|
||||
go respond(iface2, req_iface1_sol_iface2, NDP_SOL)
|
||||
|
||||
req_iface2_sol_iface1 := make(chan *NDRequest, 100)
|
||||
defer close(req_iface2_sol_iface1)
|
||||
go listen(iface2, req_iface2_sol_iface1, NDP_SOL)
|
||||
go respond(iface1, req_iface2_sol_iface1, NDP_SOL)
|
||||
|
||||
req_iface1_adv_iface2 := make(chan *NDRequest, 100)
|
||||
defer close(req_iface1_adv_iface2)
|
||||
go listen(iface1, req_iface1_adv_iface2, NDP_ADV)
|
||||
go respond(iface2, req_iface1_adv_iface2, NDP_ADV)
|
||||
|
||||
req_iface2_adv_iface1 := make(chan *NDRequest, 100)
|
||||
defer close(req_iface2_adv_iface1)
|
||||
go listen(iface2, req_iface2_adv_iface1, NDP_ADV)
|
||||
go respond(iface1, req_iface2_adv_iface1, NDP_ADV)
|
||||
|
||||
select {}
|
||||
// TODO os.signal
|
||||
|
||||
}
|
||||
|
23
packet.go
23
packet.go
@ -55,25 +55,36 @@ func (h *IPv6Header) constructPacket() []byte {
|
||||
return final
|
||||
}
|
||||
|
||||
type NDPAdvPayload struct {
|
||||
type NdpPayload struct {
|
||||
packetType NDPType
|
||||
answeringForIP []byte
|
||||
mac []byte
|
||||
}
|
||||
|
||||
func newNdpPacket(answeringForIP []byte, mac []byte) *NDPAdvPayload {
|
||||
return &NDPAdvPayload{
|
||||
func newNdpPacket(answeringForIP []byte, mac []byte, packetType NDPType) *NdpPayload {
|
||||
return &NdpPayload{
|
||||
packetType: packetType,
|
||||
answeringForIP: answeringForIP,
|
||||
mac: mac,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *NDPAdvPayload) constructPacket() ([]byte, int) {
|
||||
func (p *NdpPayload) constructPacket() ([]byte, int) {
|
||||
var protocol byte
|
||||
var flags byte
|
||||
if p.packetType == NDP_SOL {
|
||||
protocol = 0x87
|
||||
flags = 0x0
|
||||
} else {
|
||||
protocol = 0x88
|
||||
flags = 0x60
|
||||
}
|
||||
header := []byte{
|
||||
0x88, // Type: Neighbor Advertisement
|
||||
protocol, // Type: NDPType
|
||||
0x0, // Code
|
||||
0x0, // Checksum filled in later
|
||||
0x0, // Checksum filled in later
|
||||
0x60, // Flags (Solicited,Override)
|
||||
flags, // Flags (Solicited,Override)
|
||||
0x0, // Reserved
|
||||
0x0, // Reserved
|
||||
0x0, // Reserved
|
||||
|
29
rawsocket.go
29
rawsocket.go
@ -40,7 +40,7 @@ func htons(v uint16) int {
|
||||
}
|
||||
func htons16(v uint16) uint16 { return v<<8 | v>>8 }
|
||||
|
||||
func listen(iface string, responder chan *NDRequest) {
|
||||
func listen(iface string, responder chan *NDRequest, requestType NDPType) {
|
||||
|
||||
niface, err := net.InterfaceByName(iface)
|
||||
if err != nil {
|
||||
@ -68,7 +68,9 @@ func listen(iface string, responder chan *NDRequest) {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
var f Filter = []bpf.Instruction{
|
||||
var f Filter
|
||||
if requestType == NDP_SOL {
|
||||
f = []bpf.Instruction{
|
||||
// Load "EtherType" field from the ethernet header.
|
||||
bpf.LoadAbsolute{Off: 12, Size: 2},
|
||||
// Jump to the drop packet instruction if EtherType is not IPv6.
|
||||
@ -86,6 +88,26 @@ func listen(iface string, responder chan *NDRequest) {
|
||||
// Verdict is "ignore packet."
|
||||
bpf.RetConstant{Val: 0},
|
||||
}
|
||||
} else {
|
||||
f = []bpf.Instruction{
|
||||
// Load "EtherType" field from the ethernet header.
|
||||
bpf.LoadAbsolute{Off: 12, Size: 2},
|
||||
// Jump to the drop packet instruction if EtherType is not IPv6.
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x86dd, SkipTrue: 4},
|
||||
// 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.
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x3a, SkipTrue: 2},
|
||||
// Load "Type" field from ICMPv6 header.
|
||||
bpf.LoadAbsolute{Off: 54, Size: 1},
|
||||
// Jump to the drop packet instruction if Type is not Neighbor Advertisement.
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x88, SkipTrue: 1},
|
||||
// Verdict is "send up to 4k of the packet to userspace."
|
||||
bpf.RetConstant{Val: 4096},
|
||||
// Verdict is "ignore packet."
|
||||
bpf.RetConstant{Val: 0},
|
||||
}
|
||||
}
|
||||
|
||||
err = f.ApplyTo(fd)
|
||||
if err != nil {
|
||||
@ -106,9 +128,10 @@ func listen(iface string, responder chan *NDRequest) {
|
||||
fmt.Printf("% X\n", buf[:numRead][80:86])
|
||||
fmt.Println()
|
||||
responder <- &NDRequest{
|
||||
requestType: requestType,
|
||||
srcIP: buf[:numRead][22:38],
|
||||
answeringForIP: buf[:numRead][62:78],
|
||||
mac: niface.HardwareAddr,
|
||||
mac: buf[:numRead][80:86],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
responder.go
19
responder.go
@ -1,29 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var fd int
|
||||
|
||||
func respond(iface string, requests chan *NDRequest) {
|
||||
func respond(iface string, requests chan *NDRequest, respondType NDPType) {
|
||||
fd, _ = syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
|
||||
syscall.BindToDevice(fd, iface)
|
||||
|
||||
niface, err := net.InterfaceByName(iface)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
for {
|
||||
n := <-requests
|
||||
pkt(n.srcIP, n.answeringForIP, n.mac)
|
||||
pkt(n.srcIP, n.answeringForIP, niface.HardwareAddr, respondType)
|
||||
}
|
||||
}
|
||||
|
||||
func pkt(srcip []byte, tgtip []byte, mac []byte) {
|
||||
func pkt(srcip []byte, tgtip []byte, mac []byte, respondType NDPType) {
|
||||
v6 := newIpv6Header(emptyIpv6, srcip)
|
||||
NDPa := newNdpPacket(tgtip, mac)
|
||||
NDPa := newNdpPacket(tgtip, mac, respondType)
|
||||
v6.addPayload(NDPa)
|
||||
response := v6.constructPacket()
|
||||
|
||||
var t [16]byte
|
||||
if respondType == NDP_SOL {
|
||||
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{
|
||||
Port: 0,
|
||||
Addr: t,
|
||||
|
Loading…
x
Reference in New Issue
Block a user