@ -25,6 +25,7 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
"tailscale.com/net/netaddr"
"tailscale.com/net/netaddr"
"tailscale.com/net/packet"
"tailscale.com/net/packet"
"tailscale.com/net/tsaddr"
"tailscale.com/syncs"
"tailscale.com/syncs"
"tailscale.com/types/ipproto"
"tailscale.com/types/ipproto"
"tailscale.com/types/logger"
"tailscale.com/types/logger"
@ -158,7 +159,7 @@ func (t *tapDevice) handleTAPFrame(ethBuf []byte) bool {
// If the client's asking about their own IP, tell them it's
// If the client's asking about their own IP, tell them it's
// their own MAC. TODO(bradfitz): remove String allocs.
// their own MAC. TODO(bradfitz): remove String allocs.
if net . IP ( req . ProtocolAddressTarget ( ) ) . String ( ) == t heClientIP {
if net . IP ( req . ProtocolAddressTarget ( ) ) . String ( ) == t . clientIPv4 . Load ( ) {
copy ( res . HardwareAddressSender ( ) , ethSrcMAC )
copy ( res . HardwareAddressSender ( ) , ethSrcMAC )
} else {
} else {
copy ( res . HardwareAddressSender ( ) , ourMAC [ : ] )
copy ( res . HardwareAddressSender ( ) , ourMAC [ : ] )
@ -178,9 +179,12 @@ func (t *tapDevice) handleTAPFrame(ethBuf []byte) bool {
}
}
}
}
// TODO(bradfitz): remove these hard-coded values and move from a /24 to a /10 CGNAT as the range.
var (
const theClientIP = "100.70.145.3" // TODO: make dynamic from netmap
// routerIP is the IP address of the DHCP server.
const routerIP = "100.70.145.1" // must be in same netmask (currently hack at /24) as theClientIP
routerIP = net . ParseIP ( tsaddr . TailscaleServiceIPString )
// cgnatNetMask is the netmask of the 100.64.0.0/10 CGNAT range.
cgnatNetMask = net . IPMask ( net . ParseIP ( "255.192.0.0" ) . To4 ( ) )
)
// handleDHCPRequest handles receiving a raw TAP ethernet frame and reports whether
// handleDHCPRequest handles receiving a raw TAP ethernet frame and reports whether
// it's been handled as a DHCP request. That is, it reports whether the frame should
// it's been handled as a DHCP request. That is, it reports whether the frame should
@ -228,17 +232,22 @@ func (t *tapDevice) handleDHCPRequest(ethBuf []byte) bool {
}
}
switch dp . MessageType ( ) {
switch dp . MessageType ( ) {
case dhcpv4 . MessageTypeDiscover :
case dhcpv4 . MessageTypeDiscover :
ips := t . clientIPv4 . Load ( )
if ips == "" {
t . logf ( "tap: DHCP no client IP" )
return consumePacket
}
offer , err := dhcpv4 . New (
offer , err := dhcpv4 . New (
dhcpv4 . WithReply ( dp ) ,
dhcpv4 . WithReply ( dp ) ,
dhcpv4 . WithMessageType ( dhcpv4 . MessageTypeOffer ) ,
dhcpv4 . WithMessageType ( dhcpv4 . MessageTypeOffer ) ,
dhcpv4 . WithRouter ( net . ParseIP ( routerIP ) ) , // the default route
dhcpv4 . WithRouter ( routerIP) , // the default route
dhcpv4 . WithDNS ( net . ParseIP ( "100.100.100.100" ) ) ,
dhcpv4 . WithDNS ( routerIP ) ,
dhcpv4 . WithServerIP ( net. ParseIP ( "100.100.100.100" ) ) , // TODO: what is this?
dhcpv4 . WithServerIP ( routerIP ) , // TODO: what is this?
dhcpv4 . WithOption ( dhcpv4 . OptServerIdentifier ( net. ParseIP ( "100.100.100.100" ) ) ) ,
dhcpv4 . WithOption ( dhcpv4 . OptServerIdentifier ( routerIP ) ) ,
dhcpv4 . WithYourIP ( net . ParseIP ( theClientIP ) ) ,
dhcpv4 . WithYourIP ( net . ParseIP ( ips ) ) ,
dhcpv4 . WithLeaseTime ( 3600 ) , // hour works
dhcpv4 . WithLeaseTime ( 3600 ) , // hour works
//dhcpv4.WithHwAddr(ethSrcMAC),
//dhcpv4.WithHwAddr(ethSrcMAC),
dhcpv4 . WithNetmask ( net. IP Mask(net . ParseIP ( "255.255.255.0" ) . To4 ( ) ) ), // TODO: wrong
dhcpv4 . WithNetmask ( cg natN etMask ),
//dhcpv4.WithTransactionID(dp.TransactionID),
//dhcpv4.WithTransactionID(dp.TransactionID),
)
)
if err != nil {
if err != nil {
@ -258,16 +267,21 @@ func (t *tapDevice) handleDHCPRequest(ethBuf []byte) bool {
t . logf ( "tap: wrote DHCP OFFER %v, %v" , n , err )
t . logf ( "tap: wrote DHCP OFFER %v, %v" , n , err )
}
}
case dhcpv4 . MessageTypeRequest :
case dhcpv4 . MessageTypeRequest :
ips := t . clientIPv4 . Load ( )
if ips == "" {
t . logf ( "tap: DHCP no client IP" )
return consumePacket
}
ack , err := dhcpv4 . New (
ack , err := dhcpv4 . New (
dhcpv4 . WithReply ( dp ) ,
dhcpv4 . WithReply ( dp ) ,
dhcpv4 . WithMessageType ( dhcpv4 . MessageTypeAck ) ,
dhcpv4 . WithMessageType ( dhcpv4 . MessageTypeAck ) ,
dhcpv4 . WithDNS ( net . ParseIP ( "100.100.100.100" ) ) ,
dhcpv4 . WithDNS ( routerIP ) ,
dhcpv4 . WithRouter ( net . ParseIP ( routerIP ) ) , // the default route
dhcpv4 . WithRouter ( routerIP) , // the default route
dhcpv4 . WithServerIP ( net. ParseIP ( "100.100.100.100" ) ) , // TODO: what is this?
dhcpv4 . WithServerIP ( routerIP ) , // TODO: what is this?
dhcpv4 . WithOption ( dhcpv4 . OptServerIdentifier ( net. ParseIP ( "100.100.100.100" ) ) ) ,
dhcpv4 . WithOption ( dhcpv4 . OptServerIdentifier ( routerIP ) ) ,
dhcpv4 . WithYourIP ( net . ParseIP ( theClientIP ) ) , // Hello world
dhcpv4 . WithYourIP ( net . ParseIP ( ips ) ) , // Hello world
dhcpv4 . WithLeaseTime ( 3600 ) , // hour works
dhcpv4 . WithLeaseTime ( 3600 ) , // hour works
dhcpv4 . WithNetmask ( net. IP Mask( net . ParseIP ( "255.255.255.0" ) . To4 ( ) ) ) ,
dhcpv4 . WithNetmask ( cg natN etMask) ,
)
)
if err != nil {
if err != nil {
t . logf ( "error building DHCP ack: %v" , err )
t . logf ( "error building DHCP ack: %v" , err )
@ -368,15 +382,23 @@ func newTAPDevice(logf logger.Logf, fd int, tapName string) (tun.Device, error)
}
}
type tapDevice struct {
type tapDevice struct {
file * os . File
file * os . File
logf func ( format string , args ... any )
logf func ( format string , args ... any )
events chan tun . Event
events chan tun . Event
name string
name string
closeOnce sync . Once
closeOnce sync . Once
clientIPv4 syncs . AtomicValue [ string ]
destMACAtomic syncs . AtomicValue [ [ 6 ] byte ]
destMACAtomic syncs . AtomicValue [ [ 6 ] byte ]
}
}
var _ setIPer = ( * tapDevice ) ( nil )
func ( t * tapDevice ) SetIP ( ipV4 , ipV6TODO netip . Addr ) error {
t . clientIPv4 . Store ( ipV4 . String ( ) )
return nil
}
func ( t * tapDevice ) File ( ) * os . File {
func ( t * tapDevice ) File ( ) * os . File {
return t . file
return t . file
}
}