aboutsummaryrefslogblamecommitdiffstatshomepage
path: root/service/service_tunnel.go
blob: 4c9b2d63496eac303808e90f321ad0ac9a61d699 (plain) (tree)
1
2
3
4
5
6
7
8
9








                                                              
             
                                   
                                        
             

                       


                                      

                                               

                                           
                                                 


                         
                           







                                                            
                  
                                            






                                             
                   




                                                                                                                                                   
                              










                                                             
                 

                                   











                                                                                                 
         
                                    

                                             
                                                                                       


                                



                                                                                                           



                                            
                                 




                                                                                      
                                                                                       

                                                 
                                               
                       
                                                        




                                                                         



                                             

                                              

                                             
                                             

                                                                             
                                               

                      




                                                  
                                        
                         
                                              


                                                    
 


                                                                                     
                                                  

                      
                                                                         
                                              
 
                                                                   
                       
                                                                                     
                                             


                      
                                             
                       
                                                                                                            
                                             




                                                                          




                                      
                                      




                                                                                                
                                  
                              

                 
 
/* SPDX-License-Identifier: MIT
 *
 * Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
 */

package service

import (
	"bufio"
	"fmt"
	"golang.zx2c4.com/winipcfg"
	"golang.zx2c4.com/wireguard/ipc"
	"log"
	"net"
	"runtime/debug"
	"strings"

	"golang.org/x/sys/windows/svc"
	"golang.org/x/sys/windows/svc/eventlog"

	"golang.zx2c4.com/wireguard/device"
	"golang.zx2c4.com/wireguard/tun"
	"golang.zx2c4.com/wireguard/windows/conf"
)

type confElogger struct {
	elog  *eventlog.Log
	conf  *conf.Config
	level int
}

func (elog confElogger) Write(p []byte) (n int, err error) {
	msg := elog.conf.Name + ": " + string(p)
	n = len(msg)
	switch elog.level {
	case 1, 2:
		err = elog.elog.Info(1, msg)
	case 3:
		err = elog.elog.Error(1, msg)
	}
	return
}

type tunnelService struct {
	path string
}

func (service *tunnelService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) {
	changes <- svc.Status{State: svc.StartPending}

	var dev *device.Device
	var uapi net.Listener
	var routeChangeCallback *winipcfg.RouteChangeCallback
	var elog *eventlog.Log

	defer func() {
		changes <- svc.Status{State: svc.StopPending}
		if routeChangeCallback != nil {
			routeChangeCallback.Unregister()
		}
		if uapi != nil {
			uapi.Close()
		}
		if dev != nil {
			dev.Close()
		}
		if elog != nil {
			elog.Info(1, "Shutting down")
		}
	}()

	//TODO: remember to clean this up in the msi uninstaller
	eventlog.InstallAsEventCreate("WireGuard", eventlog.Info|eventlog.Warning|eventlog.Error)
	elog, err := eventlog.Open("WireGuard")
	if err != nil {
		exitCode = ERROR_LOG_CONTAINER_OPEN_FAILED
		return
	}
	log.SetOutput(elogger{elog})
	defer func() {
		if x := recover(); x != nil {
			elog.Error(1, fmt.Sprintf("%v:\n%s", x, string(debug.Stack())))
			panic(x)
		}
	}()

	conf, err := conf.LoadFromPath(service.path)
	if err != nil {
		elog.Error(1, "Unable to load configuration file from path "+service.path+": "+err.Error())
		exitCode = ERROR_OPEN_FAILED
		return
	}

	logger := &device.Logger{
		Debug: log.New(&confElogger{elog: elog, conf: conf, level: 1}, "", 0),
		Info:  log.New(&confElogger{elog: elog, conf: conf, level: 2}, "", 0),
		Error: log.New(&confElogger{elog: elog, conf: conf, level: 3}, "", 0),
	}

	logger.Info.Println("Starting wireguard-go version", device.WireGuardGoVersion)
	logger.Debug.Println("Debug log enabled")

	wintun, err := tun.CreateTUN(conf.Name)
	if err == nil {
		realInterfaceName, err2 := wintun.Name()
		if err2 == nil {
			conf.Name = realInterfaceName
		}
	} else {
		logger.Error.Println("Failed to create TUN device:", err)
		exitCode = ERROR_ADAP_HDW_ERR
		return
	}

	dev = device.NewDevice(wintun, logger)
	dev.Up()
	logger.Info.Println("Device started")

	uapi, err = ipc.UAPIListen(conf.Name)
	if err != nil {
		logger.Error.Println("Failed to listen on uapi socket:", err)
		exitCode = ERROR_PIPE_LISTENING
		return
	}

	go func() {
		for {
			conn, err := uapi.Accept()
			if err != nil {
				continue
			}
			go dev.IpcHandle(conn)
		}
	}()
	logger.Info.Println("UAPI listener started")

	uapiConf, err := conf.ToUAPI()
	if err != nil {
		logger.Error.Println("Failed to convert to UAPI serialization:", err)
		exitCode = ERROR_INVALID_PARAMETER
		return
	}
	dev.IpcSetOperation(bufio.NewReader(strings.NewReader(uapiConf)))
	guid := wintun.(*tun.NativeTun).GUID()

	routeChangeCallback, err = monitorDefaultRoutes(dev, &guid)
	if err != nil {
		logger.Error.Println("Unable to bind sockets to default route:", err)
		exitCode = ERROR_NETWORK_BUSY
		return
	}

	err = configureInterface(conf, &guid)
	if err != nil {
		logger.Error.Println("Unable to set interface addresses, routes, DNS, or IP settings:", err)
		exitCode = ERROR_NETWORK_BUSY
		return
	}

	changes <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop}

	for {
		select {
		case c := <-r:
			switch c.Cmd {
			case svc.Stop:
				return
			case svc.Interrogate:
				changes <- c.CurrentStatus
			default:
				logger.Error.Printf("Unexpected service control request #%d", c)
			}
		case <-dev.Wait():
			return
		}
	}
}