| // 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() |
| } |