|
|
@ -30,16 +30,39 @@ type PacketConner interface {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type Network struct {
|
|
|
|
type Network struct {
|
|
|
|
|
|
|
|
name string
|
|
|
|
dhcpPool netaddr.IPPrefix
|
|
|
|
dhcpPool netaddr.IPPrefix
|
|
|
|
alloced map[netaddr.IP]bool
|
|
|
|
alloced map[netaddr.IP]bool
|
|
|
|
|
|
|
|
|
|
|
|
pushRoute netaddr.IPPrefix
|
|
|
|
pushRoute netaddr.IPPrefix
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (n *Network) write(p []byte, dst, src netaddr.IPPort) (num int, err error) {
|
|
|
|
|
|
|
|
panic("TODO")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type iface struct {
|
|
|
|
type iface struct {
|
|
|
|
net *Network
|
|
|
|
net *Network
|
|
|
|
up bool
|
|
|
|
name string // optional
|
|
|
|
ips []netaddr.IP
|
|
|
|
ips []netaddr.IP // static; not mutated once created
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (f *iface) String() string {
|
|
|
|
|
|
|
|
// TODO: make this all better
|
|
|
|
|
|
|
|
if f.name != "" {
|
|
|
|
|
|
|
|
return f.name
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("unamed-interface-on-network-%p", f.net)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Contains reports whether f contains ip as an IP.
|
|
|
|
|
|
|
|
func (f *iface) Contains(ip netaddr.IP) bool {
|
|
|
|
|
|
|
|
for _, v := range f.ips {
|
|
|
|
|
|
|
|
if ip == v {
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type routeEntry struct {
|
|
|
|
type routeEntry struct {
|
|
|
@ -57,6 +80,39 @@ type Machine struct {
|
|
|
|
conns map[netaddr.IPPort]*conn
|
|
|
|
conns map[netaddr.IPPort]*conn
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
|
|
|
v4unspec = netaddr.IPv4(0, 0, 0, 0)
|
|
|
|
|
|
|
|
v6unspec = netaddr.IPv6Unspecified()
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (m *Machine) writePacket(p []byte, dst, src netaddr.IPPort) (n int, err error) {
|
|
|
|
|
|
|
|
iface, err := m.interfaceForIP(dst.IP)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return 0, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
unspec := src.IP == v4unspec || src.IP == v6unspec
|
|
|
|
|
|
|
|
if unspec {
|
|
|
|
|
|
|
|
// TODO: pick a src IP
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if !iface.Contains(src.IP) {
|
|
|
|
|
|
|
|
return 0, fmt.Errorf("can't send to %v with src %v on interface %v", dst.IP, src.IP, iface)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return iface.net.write(p, dst, src)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (m *Machine) interfaceForIP(ip netaddr.IP) (*iface, error) {
|
|
|
|
|
|
|
|
m.mu.Lock()
|
|
|
|
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
|
|
|
|
for _, re := range m.routes {
|
|
|
|
|
|
|
|
if re.prefix.Contains(ip) {
|
|
|
|
|
|
|
|
return re.iface, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("no route found to %v", ip)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *Machine) hasv6() bool {
|
|
|
|
func (m *Machine) hasv6() bool {
|
|
|
|
m.mu.Lock()
|
|
|
|
m.mu.Lock()
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
defer m.mu.Unlock()
|
|
|
@ -213,7 +269,11 @@ func (c *conn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *conn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
|
|
|
func (c *conn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
|
|
|
panic("TODO")
|
|
|
|
ipp, err := netaddr.ParseIPPort(addr.String())
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return 0, fmt.Errorf("bogus addr %T %q", addr, addr.String())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.m.writePacket(p, ipp, c.ipp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *conn) SetDeadline(t time.Time) error {
|
|
|
|
func (c *conn) SetDeadline(t time.Time) error {
|
|
|
|