mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-13 11:11:30 -04:00
Use IP_BIND_ADDRESS_NO_PORT when dialing the ORPort on Linux.
When the orport-srcaddr option is set, we bind to a source IP address before dialing the ORPort/ExtORPort. tor similarly binds to a source IP address when OutboundBindAddress is set in torrc. Since tor 0.4.7.13, tor sets IP_BIND_ADDRESS_NO_PORT, and because problems arise when some programs use IP_BIND_ADDRESS_NO_PORT and some do not, we also have to start using IP_BIND_ADDRESS_NO_PORT when we upgrade tor (tpo/anti-censorship/pluggable-transports/snowflake#40270). Related: tpo/anti-censorship/pluggable-transports/snowflake#40198
This commit is contained in:
parent
130b63ccdd
commit
9edaee6547
4 changed files with 63 additions and 1 deletions
1
go.mod
1
go.mod
|
@ -20,5 +20,6 @@ require (
|
|||
gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.4.0
|
||||
golang.org/x/crypto v0.6.0
|
||||
golang.org/x/net v0.7.0
|
||||
golang.org/x/sys v0.5.0
|
||||
google.golang.org/protobuf v1.26.0
|
||||
)
|
||||
|
|
14
server/dial.go
Normal file
14
server/dial.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package main
|
||||
|
||||
import "syscall"
|
||||
|
||||
// dialerControl does nothing.
|
||||
//
|
||||
// On Linux, this function would set the IP_BIND_ADDRESS_NO_PORT socket option
|
||||
// in preparation for a future bind-before-connect.
|
||||
func dialerControl(network, address string, c syscall.RawConn) error {
|
||||
return nil
|
||||
}
|
45
server/dial_linux.go
Normal file
45
server/dial_linux.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// dialerControl prepares a syscall.RawConn for a future bind-before-connect by
|
||||
// setting the IP_BIND_ADDRESS_NO_PORT socket option.
|
||||
//
|
||||
// On Linux, setting the IP_BIND_ADDRESS_NO_PORT socket option helps conserve
|
||||
// ephemeral ports when binding to a specific IP addresses before connecting
|
||||
// (bind before connect), by not assigning the port number when bind is called,
|
||||
// but waiting until connect. But problems arise if there are multiple processes
|
||||
// doing bind-before-connect, and some of them use IP_BIND_ADDRESS_NO_PORT and
|
||||
// some of them do not. When there is a mix, the ones that do will have their
|
||||
// ephemeral ports reserved by the ones that do not, leading to EADDRNOTAVAIL
|
||||
// errors.
|
||||
//
|
||||
// tor does bind-before-connect when the OutboundBindAddress option is set in
|
||||
// torrc. Since version 0.4.7.13 (January 2023), tor sets
|
||||
// IP_BIND_ADDRESS_NO_PORT unconditionally on platforms that support it, and
|
||||
// therefore we must do the same, to avoid EADDRNOTAVAIL errors.
|
||||
//
|
||||
// # References
|
||||
//
|
||||
// https://bugs.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/40201#note_2839472
|
||||
// https://forum.torproject.net/t/tor-relays-inet-csk-bind-conflict/5757/10
|
||||
// https://blog.cloudflare.com/how-to-stop-running-out-of-ephemeral-ports-and-start-to-love-long-lived-connections/
|
||||
// https://blog.cloudflare.com/the-quantum-state-of-a-tcp-port/
|
||||
// https://forum.torproject.net/t/stable-release-0-4-5-16-and-0-4-7-13/6216
|
||||
func dialerControl(network, address string, c syscall.RawConn) error {
|
||||
var sockErr error
|
||||
err := c.Control(func(fd uintptr) {
|
||||
sockErr = syscall.SetsockoptInt(int(fd), unix.SOL_IP, unix.IP_BIND_ADDRESS_NO_PORT, 1)
|
||||
})
|
||||
if err == nil {
|
||||
err = sockErr
|
||||
}
|
||||
return err
|
||||
}
|
|
@ -76,7 +76,9 @@ func handleConn(conn net.Conn, orPortSrcAddr *net.IPNet) error {
|
|||
addr := conn.RemoteAddr().String()
|
||||
statsChannel <- addr != ""
|
||||
|
||||
dialer := net.Dialer{}
|
||||
dialer := net.Dialer{
|
||||
Control: dialerControl,
|
||||
}
|
||||
if orPortSrcAddr != nil {
|
||||
// Use a random source IP address in the given range.
|
||||
ip, err := randIPAddr(orPortSrcAddr)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue