mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-22 21:08:38 +00:00
start to add NAT-PMP port mapping
Change-Id: Id8061ab8e907a9473f0931deebd6cabcd32deffc Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
40814eafb4
commit
ae484da02e
@ -46,6 +46,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
listen = flag.String("listen", "/tmp/qemu.sock", "path to listen on")
|
listen = flag.String("listen", "/tmp/qemu.sock", "path to listen on")
|
||||||
hard = flag.Bool("hard", false, "use hard NAT")
|
hard = flag.Bool("hard", false, "use hard NAT")
|
||||||
|
portmap = flag.Bool("portmap", false, "enable portmapping")
|
||||||
)
|
)
|
||||||
|
|
||||||
const nicID = 1
|
const nicID = 1
|
||||||
@ -84,6 +85,7 @@ func main() {
|
|||||||
|
|
||||||
s.nodes[node1.mac] = node1
|
s.nodes[node1.mac] = node1
|
||||||
net1.InitNAT(*hard)
|
net1.InitNAT(*hard)
|
||||||
|
net1.portmap = *portmap
|
||||||
net2 := &network{
|
net2 := &network{
|
||||||
s: s,
|
s: s,
|
||||||
mac: MAC{0x52, 0x54, 0x00, 0x01, 0x01, 0x2},
|
mac: MAC{0x52, 0x54, 0x00, 0x01, 0x01, 0x2},
|
||||||
@ -437,6 +439,7 @@ type network struct {
|
|||||||
s *Server
|
s *Server
|
||||||
mac MAC
|
mac MAC
|
||||||
doesNAT bool
|
doesNAT bool
|
||||||
|
portmap bool
|
||||||
wanIP netip.Addr
|
wanIP netip.Addr
|
||||||
lanIP netip.Prefix // with host bits set (e.g. 192.168.2.1/24)
|
lanIP netip.Prefix // with host bits set (e.g. 192.168.2.1/24)
|
||||||
nodesByIP map[netip.Addr]*node
|
nodesByIP map[netip.Addr]*node
|
||||||
@ -679,11 +682,18 @@ func (n *network) HandleEthernetPacket(ep EthernetPacket) {
|
|||||||
// LAN IP here and wrapped in an ethernet layer and delivered
|
// LAN IP here and wrapped in an ethernet layer and delivered
|
||||||
// to the network.
|
// to the network.
|
||||||
func (n *network) HandleUDPPacket(p UDPPacket) {
|
func (n *network) HandleUDPPacket(p UDPPacket) {
|
||||||
src := p.Src
|
|
||||||
dst := n.doNATIn(p.Src, p.Dst)
|
dst := n.doNATIn(p.Src, p.Dst)
|
||||||
if !dst.IsValid() {
|
if !dst.IsValid() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
p.Dst = dst
|
||||||
|
n.WriteUDPPacketNoNAT(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteUDPPacketNoNAT writes a UDP packet to the network, without
|
||||||
|
// doing any NAT translation.
|
||||||
|
func (n *network) WriteUDPPacketNoNAT(p UDPPacket) {
|
||||||
|
src, dst := p.Src, p.Dst
|
||||||
node, ok := n.nodesByIP[dst.Addr()]
|
node, ok := n.nodesByIP[dst.Addr()]
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Printf("no node for dest IP %v in UDP packet %v=>%v", dst.Addr(), p.Src, p.Dst)
|
log.Printf("no node for dest IP %v in UDP packet %v=>%v", dst.Addr(), p.Src, p.Dst)
|
||||||
@ -732,7 +742,7 @@ func (n *network) HandleEthernetIPv4PacketForRouter(ep EthernetPacket) {
|
|||||||
}
|
}
|
||||||
srcIP, _ := netip.AddrFromSlice(v4.SrcIP)
|
srcIP, _ := netip.AddrFromSlice(v4.SrcIP)
|
||||||
dstIP, _ := netip.AddrFromSlice(v4.DstIP)
|
dstIP, _ := netip.AddrFromSlice(v4.DstIP)
|
||||||
toForward := dstIP != n.lanIP.Addr()
|
toForward := dstIP != n.lanIP.Addr() && dstIP != netip.IPv4Unspecified()
|
||||||
udp, isUDP := packet.Layer(layers.LayerTypeUDP).(*layers.UDP)
|
udp, isUDP := packet.Layer(layers.LayerTypeUDP).(*layers.UDP)
|
||||||
|
|
||||||
if isDHCPRequest(packet) {
|
if isDHCPRequest(packet) {
|
||||||
@ -762,6 +772,15 @@ func (n *network) HandleEthernetIPv4PacketForRouter(ep EthernetPacket) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !toForward && isNATPMP(packet) {
|
||||||
|
n.handleNATPMPRequest(UDPPacket{
|
||||||
|
Src: netip.AddrPortFrom(srcIP, uint16(udp.SrcPort)),
|
||||||
|
Dst: netip.AddrPortFrom(dstIP, uint16(udp.DstPort)),
|
||||||
|
Payload: udp.Payload,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if toForward && isUDP {
|
if toForward && isUDP {
|
||||||
src := netip.AddrPortFrom(srcIP, uint16(udp.SrcPort))
|
src := netip.AddrPortFrom(srcIP, uint16(udp.SrcPort))
|
||||||
dst := netip.AddrPortFrom(dstIP, uint16(udp.DstPort))
|
dst := netip.AddrPortFrom(dstIP, uint16(udp.DstPort))
|
||||||
@ -960,6 +979,11 @@ func isDNSRequest(pkt gopacket.Packet) bool {
|
|||||||
return ok && dns.QR == false && len(dns.Questions) > 0
|
return ok && dns.QR == false && len(dns.Questions) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isNATPMP(pkt gopacket.Packet) bool {
|
||||||
|
udp, ok := pkt.Layer(layers.LayerTypeUDP).(*layers.UDP)
|
||||||
|
return ok && udp.DstPort == 5351 && len(udp.Payload) > 0 && udp.Payload[0] == 0 // version 0, not 2 for PCP
|
||||||
|
}
|
||||||
|
|
||||||
func makeSTUNReply(req UDPPacket) (res UDPPacket, ok bool) {
|
func makeSTUNReply(req UDPPacket) (res UDPPacket, ok bool) {
|
||||||
txid, err := stun.ParseBindingRequest(req.Payload)
|
txid, err := stun.ParseBindingRequest(req.Payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1128,6 +1152,31 @@ func (n *network) createARPResponse(pkt gopacket.Packet) ([]byte, error) {
|
|||||||
return buffer.Bytes(), nil
|
return buffer.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *network) handleNATPMPRequest(req UDPPacket) {
|
||||||
|
if string(req.Payload) == "\x00\x00" {
|
||||||
|
// https://www.rfc-editor.org/rfc/rfc6886#section-3.2
|
||||||
|
|
||||||
|
res := make([]byte, 0, 12)
|
||||||
|
res = append(res,
|
||||||
|
0, // version 0 (NAT-PMP)
|
||||||
|
128, // response to op 0 (128+0)
|
||||||
|
0, 0, // result code success
|
||||||
|
)
|
||||||
|
res = binary.BigEndian.AppendUint32(res, uint32(time.Now().Unix()))
|
||||||
|
wan4 := n.wanIP.As4()
|
||||||
|
res = append(res, wan4[:]...)
|
||||||
|
n.WriteUDPPacketNoNAT(UDPPacket{
|
||||||
|
Src: req.Dst,
|
||||||
|
Dst: req.Src,
|
||||||
|
Payload: res,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("TODO: handle NAT-PMP packet % 02x", req.Payload)
|
||||||
|
// TODO: handle NAT-PMP packet 00 01 00 00 ed 40 00 00 00 00 1c 20
|
||||||
|
}
|
||||||
|
|
||||||
type NetworkID string
|
type NetworkID string
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user