@ -591,16 +591,7 @@ func (b *LocalBackend) tcpHandlerForVIPService(dstAddr, srcAddr netip.AddrPort)
} )
}
errc := make ( chan error , 1 )
go func ( ) {
_ , err := io . Copy ( backConn , conn )
errc <- err
} ( )
go func ( ) {
_ , err := io . Copy ( conn , backConn )
errc <- err
} ( )
return <- errc
return b . forwardTCPWithProxyProtocol ( conn , backConn , tcph . ProxyProtocol ( ) , srcAddr , dport , backDst )
}
}
@ -678,93 +669,93 @@ func (b *LocalBackend) tcpHandlerForServe(dport uint16, srcAddr netip.AddrPort,
} )
}
var proxyHeader [ ] byte
if ver := tcph . ProxyProtocol ( ) ; ver > 0 {
// backAddr is the final "destination" of the connection,
// which is the connection to the proxied-to backend.
backAddr := backConn . RemoteAddr ( ) . ( * net . TCPAddr )
// We always want to format the PROXY protocol
// header based on the IPv4 or IPv6-ness of
// the client. The SourceAddr and
// DestinationAddr need to match in type, so we
// need to be careful to not e.g. set a
// SourceAddr of type IPv6 and DestinationAddr
// of type IPv4.
//
// If this is an IPv6-mapped IPv4 address,
// though, unmap it.
proxySrcAddr := srcAddr
if proxySrcAddr . Addr ( ) . Is4In6 ( ) {
proxySrcAddr = netip . AddrPortFrom (
proxySrcAddr . Addr ( ) . Unmap ( ) ,
proxySrcAddr . Port ( ) ,
)
}
is4 := proxySrcAddr . Addr ( ) . Is4 ( )
// TODO(bradfitz): do the RegisterIPPortIdentity and
// UnregisterIPPortIdentity stuff that netstack does
return b . forwardTCPWithProxyProtocol ( conn , backConn , tcph . ProxyProtocol ( ) , srcAddr , dport , backDst )
}
}
var destAddr netip . Addr
if self := b . currentNode ( ) . Self ( ) ; self . Valid ( ) {
if is4 {
destAddr = nodeIP ( self , netip . Addr . Is4 )
} else {
destAddr = nodeIP ( self , netip . Addr . Is6 )
}
}
if ! destAddr . IsValid ( ) {
// Pick a best-effort destination address of localhost.
if is4 {
destAddr = netip . AddrFrom4 ( [ 4 ] byte { 127 , 0 , 0 , 1 } )
} else {
destAddr = netip . IPv6Loopback ( )
}
}
return nil
}
header := & proxyproto . Header {
Version : byte ( ver ) ,
Command : proxyproto . PROXY ,
SourceAddr : net . TCPAddrFromAddrPort ( proxySrcAddr ) ,
DestinationAddr : & net . TCPAddr {
IP : destAddr . AsSlice ( ) ,
Port : backAddr . Port ,
} ,
}
if is4 {
header . TransportProtocol = proxyproto . TCPv4
} else {
header . TransportProtocol = proxyproto . TCPv6
}
var err error
proxyHeader , err = header . Format ( )
if err != nil {
b . logf ( "localbackend: failed to format proxy protocol header for port %v (from %v) to %s: %v" , dport , srcAddr , backDst , err )
}
// forwardTCPWithProxyProtocol forwards TCP traffic between conn and backConn,
// optionally prepending a PROXY protocol header if proxyProtoVer > 0.
// The srcAddr is the original client address used to build the PROXY header.
func ( b * LocalBackend ) forwardTCPWithProxyProtocol ( conn , backConn net . Conn , proxyProtoVer int , srcAddr netip . AddrPort , dport uint16 , backDst string ) error {
var proxyHeader [ ] byte
if proxyProtoVer > 0 {
backAddr := backConn . RemoteAddr ( ) . ( * net . TCPAddr )
// We always want to format the PROXY protocol header based on
// the IPv4 or IPv6-ness of the client. The SourceAddr and
// DestinationAddr need to match in type.
// If this is an IPv6-mapped IPv4 address, unmap it.
proxySrcAddr := srcAddr
if proxySrcAddr . Addr ( ) . Is4In6 ( ) {
proxySrcAddr = netip . AddrPortFrom (
proxySrcAddr . Addr ( ) . Unmap ( ) ,
proxySrcAddr . Port ( ) ,
)
}
is4 := proxySrcAddr . Addr ( ) . Is4 ( )
var destAddr netip . Addr
if self := b . currentNode ( ) . Self ( ) ; self . Valid ( ) {
if is4 {
destAddr = nodeIP ( self , netip . Addr . Is4 )
} else {
destAddr = nodeIP ( self , netip . Addr . Is6 )
}
}
if ! destAddr . IsValid ( ) {
// Unexpected: we couldn't determine the node's IP address.
// Pick a best-effort destination address of localhost.
if is4 {
destAddr = netip . AddrFrom4 ( [ 4 ] byte { 127 , 0 , 0 , 1 } )
} else {
destAddr = netip . IPv6Loopback ( )
}
}
// TODO(bradfitz): do the RegisterIPPortIdentity and
// UnregisterIPPortIdentity stuff that netstack does
errc := make ( chan error , 1 )
go func ( ) {
if len ( proxyHeader ) > 0 {
if _ , err := backConn . Write ( proxyHeader ) ; err != nil {
errc <- err
backConn . Close ( ) // to ensure that the other side gets EOF
return
}
}
_ , err := io . Copy ( backConn , conn )
errc <- err
} ( )
go func ( ) {
_ , err := io . Copy ( conn , backConn )
errc <- err
} ( )
return <- errc
header := & proxyproto . Header {
Version : byte ( proxyProtoVer ) ,
Command : proxyproto . PROXY ,
SourceAddr : net . TCPAddrFromAddrPort ( proxySrcAddr ) ,
DestinationAddr : & net . TCPAddr {
IP : destAddr . AsSlice ( ) ,
Port : backAddr . Port ,
} ,
}
if is4 {
header . TransportProtocol = proxyproto . TCPv4
} else {
header . TransportProtocol = proxyproto . TCPv6
}
var err error
proxyHeader , err = header . Format ( )
if err != nil {
b . logf ( "localbackend: failed to format proxy protocol header for port %v (from %v) to %s: %v" , dport , srcAddr , backDst , err )
}
}
return nil
errc := make ( chan error , 1 )
go func ( ) {
if len ( proxyHeader ) > 0 {
if _ , err := backConn . Write ( proxyHeader ) ; err != nil {
errc <- err
backConn . Close ( )
return
}
}
_ , err := io . Copy ( backConn , conn )
errc <- err
} ( )
go func ( ) {
_ , err := io . Copy ( conn , backConn )
errc <- err
} ( )
return <- errc
}
func ( b * LocalBackend ) getServeHandler ( r * http . Request ) ( _ ipn . HTTPHandlerView , at string , ok bool ) {