This repository has been archived by the owner on Feb 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #178 from stealthrocket/network
add internal/network package
- Loading branch information
Showing
24 changed files
with
3,263 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
package htls | ||
|
||
const Level = 0x74696d65 | ||
const Option = 1 | ||
|
||
const ServerName = 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,26 @@ | ||
// Package ipam contains types to implement IP address management on IPv4 and | ||
// IPv6 networks. | ||
package ipam | ||
|
||
import "net/netip" | ||
|
||
// Pool is an interface implemented by the IPv4Pool and IPv6Pool types to | ||
// abstract the type of IP addresses that are managed by the pool. | ||
type Pool interface { | ||
// Obtains the next IP address, or returns nil if the pool was exhausted. | ||
GetAddr() (netip.Addr, bool) | ||
// Returns an IP address to the pool. The ip address must have been obtained | ||
// by a previous call to GetIP or the method panics. | ||
PutAddr(netip.Addr) | ||
} | ||
|
||
// NewPool constructs a pool of IP addresses for the network passed as argument. | ||
func NewPool(prefix netip.Prefix) Pool { | ||
addr := prefix.Addr() | ||
bits := prefix.Bits() | ||
if addr.Is4() { | ||
return NewIPv4Pool(addr.As4(), bits) | ||
} else { | ||
return NewIPv6Pool(addr.As16(), bits) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package network | ||
|
||
import "net" | ||
|
||
func Host() Namespace { return hostNamespace{} } | ||
|
||
type hostNamespace struct{} | ||
|
||
func (hostNamespace) InterfaceByIndex(index int) (Interface, error) { | ||
i, err := net.InterfaceByIndex(index) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return hostInterface{i}, nil | ||
} | ||
|
||
func (hostNamespace) InterfaceByName(name string) (Interface, error) { | ||
i, err := net.InterfaceByName(name) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return hostInterface{i}, nil | ||
} | ||
|
||
func (hostNamespace) Interfaces() ([]Interface, error) { | ||
interfaces, err := net.Interfaces() | ||
if err != nil { | ||
return nil, err | ||
} | ||
hostInterfaces := make([]Interface, len(interfaces)) | ||
for i := range interfaces { | ||
hostInterfaces[i] = hostInterface{&interfaces[i]} | ||
} | ||
return hostInterfaces, nil | ||
} | ||
|
||
type hostInterface struct{ *net.Interface } | ||
|
||
func (i hostInterface) Index() int { return i.Interface.Index } | ||
|
||
func (i hostInterface) MTU() int { return i.Interface.MTU } | ||
|
||
func (i hostInterface) Name() string { return i.Interface.Name } | ||
|
||
func (i hostInterface) HardwareAddr() net.HardwareAddr { return i.Interface.HardwareAddr } | ||
|
||
func (i hostInterface) Flags() net.Flags { return i.Interface.Flags } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package network | ||
|
||
import ( | ||
"syscall" | ||
|
||
"golang.org/x/sys/unix" | ||
) | ||
|
||
func (hostNamespace) Socket(family Family, socktype Socktype, protocol Protocol) (Socket, error) { | ||
syscall.ForkLock.RLock() | ||
defer syscall.ForkLock.RUnlock() | ||
fd, err := ignoreEINTR2(func() (int, error) { | ||
return unix.Socket(int(family), int(socktype), int(protocol)) | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if err := setCloseOnExecAndNonBlocking(fd); err != nil { | ||
unix.Close(fd) | ||
return nil, err | ||
} | ||
return newHostSocket(fd, family, socktype), nil | ||
} | ||
|
||
func (s *hostSocket) Accept() (Socket, Sockaddr, error) { | ||
fd := s.fd.acquire() | ||
if fd < 0 { | ||
return nil, nil, EBADF | ||
} | ||
defer s.fd.release(fd) | ||
syscall.ForkLock.RLock() | ||
defer syscall.ForkLock.RUnlock() | ||
conn, addr, err := ignoreEINTR3(func() (int, Sockaddr, error) { | ||
return unix.Accept(fd) | ||
}) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
if err := setCloseOnExecAndNonBlocking(conn); err != nil { | ||
unix.Close(conn) | ||
return nil, nil, err | ||
} | ||
return newHostSocket(conn, s.family, s.socktype), addr, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package network | ||
|
||
import "golang.org/x/sys/unix" | ||
|
||
func (hostNamespace) Socket(family Family, socktype Socktype, protocol Protocol) (Socket, error) { | ||
fd, err := ignoreEINTR2(func() (int, error) { | ||
return unix.Socket(int(family), int(socktype)|unix.SOCK_CLOEXEC|unix.SOCK_NONBLOCK, int(protocol)) | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return newHostSocket(fd, family, socktype), nil | ||
} | ||
|
||
func (s *hostSocket) Accept() (Socket, Sockaddr, error) { | ||
fd := s.fd.acquire() | ||
if fd < 0 { | ||
return nil, nil, EBADF | ||
} | ||
defer s.fd.release(fd) | ||
conn, addr, err := ignoreEINTR3(func() (int, unix.Sockaddr, error) { | ||
return unix.Accept4(fd, unix.SOCK_CLOEXEC|unix.SOCK_NONBLOCK) | ||
}) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
return newHostSocket(conn, s.family, s.socktype), addr, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package network_test | ||
|
||
import ( | ||
"net" | ||
"testing" | ||
|
||
"github.com/stealthrocket/timecraft/internal/assert" | ||
"github.com/stealthrocket/timecraft/internal/network" | ||
) | ||
|
||
func TestHostNetwork(t *testing.T) { | ||
tests := []struct { | ||
scenario string | ||
function func(*testing.T, network.Namespace) | ||
}{ | ||
{ | ||
scenario: "a host network namespace has at least one loopback interface", | ||
function: testHostNetworkInterface, | ||
}, | ||
|
||
{ | ||
scenario: "ipv4 stream sockets can connect to one another on the loopback interface", | ||
function: testNamespaceConnectStreamLoopbackIPv4, | ||
}, | ||
|
||
{ | ||
scenario: "ipv6 stream sockets can connect to one another on the loopback interface", | ||
function: testNamespaceConnectStreamLoopbackIPv6, | ||
}, | ||
|
||
{ | ||
scenario: "ipv4 datagram sockets can connect to one another on the loopback interface", | ||
function: testNamespaceConnectDatagramLoopbackIPv4, | ||
}, | ||
|
||
{ | ||
scenario: "ipv6 datagram sockets can connect to one another on the loopback interface", | ||
function: testNamespaceConnectDatagramLoopbackIPv6, | ||
}, | ||
|
||
{ | ||
scenario: "ipv4 sockets can exchange datagrams on the loopback interface", | ||
function: testNamespaceExchangeDatagramLoopbackIPv4, | ||
}, | ||
|
||
{ | ||
scenario: "ipv6 sockets can exchange datagrams on the loopback interface", | ||
function: testNamespaceExchangeDatagramLoopbackIPv6, | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(test.scenario, func(t *testing.T) { | ||
test.function(t, network.Host()) | ||
}) | ||
} | ||
} | ||
|
||
func testHostNetworkInterface(t *testing.T, ns network.Namespace) { | ||
ifaces, err := ns.Interfaces() | ||
assert.OK(t, err) | ||
|
||
for _, iface := range ifaces { | ||
if (iface.Flags() & net.FlagLoopback) == 0 { | ||
continue | ||
} | ||
if (iface.Flags() & net.FlagUp) == 0 { | ||
continue | ||
} | ||
|
||
lo0 := iface | ||
assert.NotEqual(t, lo0.Name(), "") | ||
|
||
lo0Addrs, err := lo0.Addrs() | ||
assert.OK(t, err) | ||
|
||
ipv4 := false | ||
ipv6 := false | ||
for _, addr := range lo0Addrs { | ||
switch addr.String() { | ||
case "127.0.0.1/8": | ||
ipv4 = true | ||
case "::1/128": | ||
ipv6 = true | ||
} | ||
} | ||
assert.True(t, ipv4 && ipv6) | ||
return | ||
} | ||
|
||
t.Fatal("host network has not loopback interface") | ||
} |
Oops, something went wrong.