start to handle L2 vs L3 properly

Change-Id: I0efc9320aff419dc4b3e97c623c9af7f9d5dd48a
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2024-07-27 12:29:34 -07:00
parent c860129eb0
commit e617cf5af8

View File

@ -263,7 +263,7 @@ func (n *network) acceptTCP(r *tcp.ForwarderRequest) {
if reqDetails.LocalPort == 123 { if reqDetails.LocalPort == 123 {
r.Complete(false) r.Complete(false)
tc := gonet.NewTCPConn(&wq, ep) tc := gonet.NewTCPConn(&wq, ep)
io.WriteString(tc, "Hello Andrew from Go\nGoodbye.\n") io.WriteString(tc, "Hello from Go\nGoodbye.\n")
tc.Close() tc.Close()
return return
} }
@ -300,8 +300,16 @@ func (ep EthernetPacket) SrcMAC() MAC {
return MAC(ep.le.SrcMAC) return MAC(ep.le.SrcMAC)
} }
func (ep EthernetPacket) DstMAC() MAC {
return MAC(ep.le.DstMAC)
}
type MAC [6]byte type MAC [6]byte
func (m MAC) IsBroadcast() bool {
return m == MAC{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
}
func macOf(hwa net.HardwareAddr) (_ MAC, ok bool) { func macOf(hwa net.HardwareAddr) (_ MAC, ok bool) {
if len(hwa) != 6 { if len(hwa) != 6 {
return MAC{}, false return MAC{}, false
@ -461,20 +469,39 @@ func (s *Server) serveConn(uc net.Conn) {
} }
} }
// writeEth writes a raw Ethernet frame to all (0, 1, or multiple) connected
// clients on the network.
//
// This only delivers to client devices and not the virtual router/gateway
// device.
func (n *network) writeEth(res []byte) { func (n *network) writeEth(res []byte) {
if len(res) < 6 { if len(res) < 12 {
return return
} }
dstMAC := MAC(res[0:6]) dstMAC := MAC(res[0:6])
srcMAC := MAC(res[6:12])
if dstMAC.IsBroadcast() {
n.writeFunc.Range(func(mac MAC, writeFunc func([]byte)) bool {
writeFunc(res)
return true
})
return
}
if srcMAC == dstMAC {
log.Printf("dropping write of packet from %v to itself", srcMAC)
return
}
if writeFunc, ok := n.writeFunc.Load(dstMAC); ok { if writeFunc, ok := n.writeFunc.Load(dstMAC); ok {
writeFunc(res) writeFunc(res)
return
} }
} }
func (n *network) HandleEthernetPacket(ep EthernetPacket) { func (n *network) HandleEthernetPacket(ep EthernetPacket) {
packet := ep.gp packet := ep.gp
s := n.s dstMAC := ep.DstMAC()
writePkt := n.writeEth isBroadcast := dstMAC.IsBroadcast()
forRouter := dstMAC == n.mac || isBroadcast
switch ep.le.EthernetType { switch ep.le.EthernetType {
default: default:
@ -485,7 +512,7 @@ func (n *network) HandleEthernetPacket(ep EthernetPacket) {
if err != nil { if err != nil {
log.Printf("createARPResponse: %v", err) log.Printf("createARPResponse: %v", err)
} else { } else {
writePkt(res) n.writeEth(res)
} }
return return
case layers.EthernetTypeIPv6: case layers.EthernetTypeIPv6:
@ -496,8 +523,26 @@ func (n *network) HandleEthernetPacket(ep EthernetPacket) {
// Below // Below
} }
// Send ethernet broadcasts and unicast ethernet frames to peers
// on the same network. This is all LAN traffic that isn't meant
// for the router/gw itself:
n.writeEth(ep.gp.Data())
if forRouter {
n.HandleEthernetIPv4PacketForRouter(ep)
}
}
// HandleEthernetIPv4PacketForRouter handles an IPv4 packet that is
// directed to the router/gateway itself. The packet may be to the
// broadcast MAC address, or to the router's MAC address. The target
// IP may be the router's IP, or an internet (routed) IP.
func (n *network) HandleEthernetIPv4PacketForRouter(ep EthernetPacket) {
packet := ep.gp
writePkt := n.writeEth
if isDHCPRequest(packet) { if isDHCPRequest(packet) {
res, err := s.createDHCPResponse(packet) res, err := n.s.createDHCPResponse(packet)
if err != nil { if err != nil {
log.Printf("createDHCPResponse: %v", err) log.Printf("createDHCPResponse: %v", err)
return return
@ -512,7 +557,7 @@ func (n *network) HandleEthernetPacket(ep EthernetPacket) {
} }
if isDNSRequest(packet) { if isDNSRequest(packet) {
res, err := s.createDNSResponse(packet) res, err := n.s.createDNSResponse(packet)
if err != nil { if err != nil {
log.Printf("createDNSResponse: %v", err) log.Printf("createDNSResponse: %v", err)
return return
@ -523,7 +568,7 @@ func (n *network) HandleEthernetPacket(ep EthernetPacket) {
if isSTUNRequest(packet) { if isSTUNRequest(packet) {
log.Printf("STUN request in") log.Printf("STUN request in")
res, err := s.createSTUNResponse(packet) res, err := n.s.createSTUNResponse(packet)
if err != nil { if err != nil {
log.Printf("createSTUNResponse: %v", err) log.Printf("createSTUNResponse: %v", err)
return return
@ -541,12 +586,6 @@ func (n *network) HandleEthernetPacket(ep EthernetPacket) {
Payload: buffer.MakeWithData(pktCopy), Payload: buffer.MakeWithData(pktCopy),
}) })
n.linkEP.InjectInbound(header.IPv4ProtocolNumber, packetBuf) n.linkEP.InjectInbound(header.IPv4ProtocolNumber, packetBuf)
// var list stack.PacketBufferList
// list.PushBack(packetBuf)
// n, err := s.linkEP.WritePackets(list)
// log.Printf("Injected: %v, %v", n, err)
packetBuf.DecRef() packetBuf.DecRef()
return return
} }