blob: 8ca84cec1f65122f7f2a8abd1ff9bde2e01710ca [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package netstack
import (
"flag"
"log"
"os"
"reflect"
"runtime"
"syscall/zx"
"syscall/zx/fidl"
"app/context"
"syslog"
"netstack/connectivity"
"netstack/dns"
"netstack/filter"
"netstack/link/eth"
"fidl/fuchsia/devicesettings"
"fidl/fuchsia/net"
"fidl/fuchsia/net/stack"
"fidl/fuchsia/netstack"
"github.com/google/netstack/tcpip"
"github.com/google/netstack/tcpip/network/arp"
"github.com/google/netstack/tcpip/network/ipv4"
"github.com/google/netstack/tcpip/network/ipv6"
tcpipstack "github.com/google/netstack/tcpip/stack"
"github.com/google/netstack/tcpip/transport/icmp"
"github.com/google/netstack/tcpip/transport/tcp"
"github.com/google/netstack/tcpip/transport/udp"
)
func Main() {
flags := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
sniff := flags.Bool("sniff", false, "Enable the sniffer")
if err := flags.Parse(os.Args[1:]); err != nil {
panic(err)
}
ctx := context.CreateFromStartupInfo()
s, err := syslog.ConnectToLogger(ctx.Connector())
if err != nil {
panic(err)
}
l, err := syslog.NewLogger(syslog.LogInitOptions{
LogLevel: syslog.DebugLevel,
LogToSocket: 1,
LogToWriter: 1,
MinSeverityForFileAndLineInfo: syslog.InfoLevel,
Socket: s,
Tags: []string{"netstack"},
})
if err != nil {
panic(err)
}
syslog.SetDefaultLogger(l)
log.SetOutput(&syslog.Writer{Logger: l})
log.SetFlags(log.Lshortfile)
stk := tcpipstack.New([]string{
ipv4.ProtocolName,
ipv6.ProtocolName,
arp.ProtocolName,
}, []string{
icmp.ProtocolName4,
tcp.ProtocolName,
udp.ProtocolName,
}, tcpipstack.Options{
HandleLocal: true,
})
if err := stk.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SACKEnabled(true)); err != nil {
syslog.Fatalf("method SetTransportProtocolOption(%v, tcp.SACKEnabled(true)) failed: %v", tcp.ProtocolNumber, err)
}
arena, err := eth.NewArena()
if err != nil {
syslog.Fatalf("ethernet: %s", err)
}
req, ds, err := devicesettings.NewDeviceSettingsManagerInterfaceRequest()
if err != nil {
syslog.Fatalf("could not connect to device settings service: %s", err)
}
ctx.ConnectToEnvService(req)
ns := &Netstack{
arena: arena,
dnsClient: dns.NewClient(stk),
deviceSettings: ds,
sniff: *sniff,
}
ns.mu.ifStates = make(map[tcpip.NICID]*ifState)
ns.mu.stack = stk
if err := ns.addLoopback(); err != nil {
syslog.Fatalf("loopback: %s", err)
}
var netstackService netstack.NetstackService
ns.OnInterfacesChanged = func(interfaces2 []netstack.NetInterface2) {
connectivity.InferAndNotify(interfaces2)
// TODO(NET-2078): Switch to the new NetInterface struct once Chromium stops
// using netstack.fidl.
interfaces := interfaces2ListToInterfacesList(interfaces2)
for _, key := range netstackService.BindingKeys() {
if p, ok := netstackService.EventProxyFor(key); ok {
if err := p.OnInterfacesChanged(interfaces); err != nil {
syslog.Warnf("OnInterfacesChanged failed: %v", err)
}
}
}
}
stats := reflect.ValueOf(stk.Stats())
ctx.OutgoingService.AddObjects("counters", &context.DirectoryWrapper{
Directory: &context.DirectoryWrapper{
Directory: &statCounterInspectImpl{
name: "Networking Stat Counters",
Value: stats,
},
},
})
netstackImpl := &netstackImpl{
ns: ns,
getIO: (&context.DirectoryWrapper{
Directory: &reflectNode{
Value: stats,
},
}).GetDirectory,
}
ctx.OutgoingService.AddService(netstack.NetstackName, func(c zx.Channel) error {
k, err := netstackService.Add(netstackImpl, c, nil)
if err != nil {
syslog.Fatalf("%v", err)
}
// Send a synthetic InterfacesChanged event to each client when they join
// Prevents clients from having to race GetInterfaces / InterfacesChanged.
if p, ok := netstackService.EventProxyFor(k); ok {
ns.mu.Lock()
interfaces2 := ns.getNetInterfaces2Locked()
interfaces := interfaces2ListToInterfacesList(interfaces2)
ns.mu.Unlock()
if err := p.OnInterfacesChanged(interfaces); err != nil {
syslog.Warnf("OnInterfacesChanged failed: %v", err)
}
}
return nil
})
var dnsService netstack.ResolverAdminService
ctx.OutgoingService.AddService(netstack.ResolverAdminName, func(c zx.Channel) error {
_, err := dnsService.Add(&dnsImpl{ns: ns}, c, nil)
return err
})
var stackService stack.StackService
ctx.OutgoingService.AddService(stack.StackName, func(c zx.Channel) error {
_, err := stackService.Add(&stackImpl{ns: ns}, c, nil)
return err
})
var socketProvider net.SocketProviderService
ctx.OutgoingService.AddService(net.SocketProviderName, func(c zx.Channel) error {
_, err := socketProvider.Add(&socketProviderImpl{ns: ns}, c, nil)
return err
})
if err := connectivity.AddOutgoingService(ctx); err != nil {
syslog.Fatalf("%v", err)
}
f := filter.New(stk.PortManager)
if err := filter.AddOutgoingService(ctx, f); err != nil {
syslog.Fatalf("%v", err)
}
ns.filter = f
go pprofListen()
for i := 1; i < runtime.NumCPU(); i++ {
go fidl.Serve()
}
fidl.Serve()
}