github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/tcpip/link/tun/device.go (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tun
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/nicocha30/gvisor-ligolo/pkg/buffer"
    21  	"github.com/nicocha30/gvisor-ligolo/pkg/context"
    22  	"github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr"
    23  	"github.com/nicocha30/gvisor-ligolo/pkg/sync"
    24  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip"
    25  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip/header"
    26  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip/link/channel"
    27  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip/link/packetsocket"
    28  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip/stack"
    29  	"github.com/nicocha30/gvisor-ligolo/pkg/waiter"
    30  )
    31  
    32  const (
    33  	// drivers/net/tun.c:tun_net_init()
    34  	defaultDevMtu = 1500
    35  
    36  	// Queue length for outbound packet, arriving at fd side for read. Overflow
    37  	// causes packet drops. gVisor implementation-specific.
    38  	defaultDevOutQueueLen = 1024
    39  )
    40  
    41  var zeroMAC [6]byte
    42  
    43  // Device is an opened /dev/net/tun device.
    44  //
    45  // +stateify savable
    46  type Device struct {
    47  	waiter.Queue
    48  
    49  	mu           sync.RWMutex `state:"nosave"`
    50  	endpoint     *tunEndpoint
    51  	notifyHandle *channel.NotificationHandle
    52  	flags        Flags
    53  }
    54  
    55  // Flags set properties of a Device
    56  type Flags struct {
    57  	TUN          bool
    58  	TAP          bool
    59  	NoPacketInfo bool
    60  }
    61  
    62  // beforeSave is invoked by stateify.
    63  func (d *Device) beforeSave() {
    64  	d.mu.Lock()
    65  	defer d.mu.Unlock()
    66  	// TODO(b/110961832): Restore the device to stack. At this moment, the stack
    67  	// is not savable.
    68  	if d.endpoint != nil {
    69  		panic("/dev/net/tun does not support save/restore when a device is associated with it.")
    70  	}
    71  }
    72  
    73  // Release implements fs.FileOperations.Release.
    74  func (d *Device) Release(ctx context.Context) {
    75  	d.mu.Lock()
    76  	defer d.mu.Unlock()
    77  
    78  	// Decrease refcount if there is an endpoint associated with this file.
    79  	if d.endpoint != nil {
    80  		d.endpoint.Drain()
    81  		d.endpoint.RemoveNotify(d.notifyHandle)
    82  		d.endpoint.DecRef(ctx)
    83  		d.endpoint = nil
    84  	}
    85  }
    86  
    87  // SetIff services TUNSETIFF ioctl(2) request.
    88  func (d *Device) SetIff(s *stack.Stack, name string, flags Flags) error {
    89  	d.mu.Lock()
    90  	defer d.mu.Unlock()
    91  
    92  	if d.endpoint != nil {
    93  		return linuxerr.EINVAL
    94  	}
    95  
    96  	// Input validation.
    97  	if flags.TAP && flags.TUN || !flags.TAP && !flags.TUN {
    98  		return linuxerr.EINVAL
    99  	}
   100  
   101  	prefix := "tun"
   102  	if flags.TAP {
   103  		prefix = "tap"
   104  	}
   105  
   106  	linkCaps := stack.CapabilityNone
   107  	if flags.TAP {
   108  		linkCaps |= stack.CapabilityResolutionRequired
   109  	}
   110  
   111  	endpoint, err := attachOrCreateNIC(s, name, prefix, linkCaps)
   112  	if err != nil {
   113  		return linuxerr.EINVAL
   114  	}
   115  
   116  	d.endpoint = endpoint
   117  	d.notifyHandle = d.endpoint.AddNotify(d)
   118  	d.flags = flags
   119  	return nil
   120  }
   121  
   122  func attachOrCreateNIC(s *stack.Stack, name, prefix string, linkCaps stack.LinkEndpointCapabilities) (*tunEndpoint, error) {
   123  	for {
   124  		// 1. Try to attach to an existing NIC.
   125  		if name != "" {
   126  			if linkEP := s.GetLinkEndpointByName(name); linkEP != nil {
   127  				endpoint, ok := linkEP.(*tunEndpoint)
   128  				if !ok {
   129  					// Not a NIC created by tun device.
   130  					return nil, linuxerr.EOPNOTSUPP
   131  				}
   132  				if !endpoint.TryIncRef() {
   133  					// Race detected: NIC got deleted in between.
   134  					continue
   135  				}
   136  				return endpoint, nil
   137  			}
   138  		}
   139  
   140  		// 2. Creating a new NIC.
   141  		id := tcpip.NICID(s.UniqueID())
   142  		endpoint := &tunEndpoint{
   143  			Endpoint: channel.New(defaultDevOutQueueLen, defaultDevMtu, ""),
   144  			stack:    s,
   145  			nicID:    id,
   146  			name:     name,
   147  			isTap:    prefix == "tap",
   148  		}
   149  		endpoint.InitRefs()
   150  		endpoint.Endpoint.LinkEPCapabilities = linkCaps
   151  		if endpoint.name == "" {
   152  			endpoint.name = fmt.Sprintf("%s%d", prefix, id)
   153  		}
   154  		err := s.CreateNICWithOptions(endpoint.nicID, packetsocket.New(endpoint), stack.NICOptions{
   155  			Name: endpoint.name,
   156  		})
   157  		switch err.(type) {
   158  		case nil:
   159  			return endpoint, nil
   160  		case *tcpip.ErrDuplicateNICID:
   161  			// Race detected: A NIC has been created in between.
   162  			continue
   163  		default:
   164  			return nil, linuxerr.EINVAL
   165  		}
   166  	}
   167  }
   168  
   169  // MTU returns the tun enpoint MTU (maximum transmission unit).
   170  func (d *Device) MTU() (uint32, error) {
   171  	d.mu.RLock()
   172  	endpoint := d.endpoint
   173  	d.mu.RUnlock()
   174  	if endpoint == nil {
   175  		return 0, linuxerr.EBADFD
   176  	}
   177  	if !endpoint.IsAttached() {
   178  		return 0, linuxerr.EIO
   179  	}
   180  	return endpoint.MTU(), nil
   181  }
   182  
   183  // Write inject one inbound packet to the network interface.
   184  func (d *Device) Write(data *buffer.View) (int64, error) {
   185  	d.mu.RLock()
   186  	endpoint := d.endpoint
   187  	d.mu.RUnlock()
   188  	if endpoint == nil {
   189  		return 0, linuxerr.EBADFD
   190  	}
   191  	if !endpoint.IsAttached() {
   192  		return 0, linuxerr.EIO
   193  	}
   194  
   195  	dataLen := int64(data.Size())
   196  
   197  	// Packet information.
   198  	var pktInfoHdr PacketInfoHeader
   199  	if !d.flags.NoPacketInfo {
   200  		if dataLen < PacketInfoHeaderSize {
   201  			// Ignore bad packet.
   202  			return dataLen, nil
   203  		}
   204  		pktInfoHdrView := data.Clone()
   205  		defer pktInfoHdrView.Release()
   206  		pktInfoHdrView.CapLength(PacketInfoHeaderSize)
   207  		pktInfoHdr = PacketInfoHeader(pktInfoHdrView.AsSlice())
   208  		data.TrimFront(PacketInfoHeaderSize)
   209  	}
   210  
   211  	// Ethernet header (TAP only).
   212  	var ethHdr header.Ethernet
   213  	if d.flags.TAP {
   214  		if data.Size() < header.EthernetMinimumSize {
   215  			// Ignore bad packet.
   216  			return dataLen, nil
   217  		}
   218  		ethHdrView := data.Clone()
   219  		defer ethHdrView.Release()
   220  		ethHdrView.CapLength(header.EthernetMinimumSize)
   221  		ethHdr = header.Ethernet(ethHdrView.AsSlice())
   222  		data.TrimFront(header.EthernetMinimumSize)
   223  	}
   224  
   225  	// Try to determine network protocol number, default zero.
   226  	var protocol tcpip.NetworkProtocolNumber
   227  	switch {
   228  	case pktInfoHdr != nil:
   229  		protocol = pktInfoHdr.Protocol()
   230  	case ethHdr != nil:
   231  		protocol = ethHdr.Type()
   232  	case d.flags.TUN:
   233  		// TUN interface with IFF_NO_PI enabled, thus
   234  		// we need to determine protocol from version field
   235  		version := data.AsSlice()[0] >> 4
   236  		if version == 4 {
   237  			protocol = header.IPv4ProtocolNumber
   238  		} else if version == 6 {
   239  			protocol = header.IPv6ProtocolNumber
   240  		}
   241  	}
   242  
   243  	pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   244  		ReserveHeaderBytes: len(ethHdr),
   245  		Payload:            buffer.MakeWithView(data.Clone()),
   246  	})
   247  	defer pkt.DecRef()
   248  	copy(pkt.LinkHeader().Push(len(ethHdr)), ethHdr)
   249  	endpoint.InjectInbound(protocol, pkt)
   250  	return dataLen, nil
   251  }
   252  
   253  // Read reads one outgoing packet from the network interface.
   254  func (d *Device) Read() (*buffer.View, error) {
   255  	d.mu.RLock()
   256  	endpoint := d.endpoint
   257  	d.mu.RUnlock()
   258  	if endpoint == nil {
   259  		return nil, linuxerr.EBADFD
   260  	}
   261  
   262  	pkt := endpoint.Read()
   263  	if pkt.IsNil() {
   264  		return nil, linuxerr.ErrWouldBlock
   265  	}
   266  	v := d.encodePkt(pkt)
   267  	pkt.DecRef()
   268  	return v, nil
   269  }
   270  
   271  // encodePkt encodes packet for fd side.
   272  func (d *Device) encodePkt(pkt stack.PacketBufferPtr) *buffer.View {
   273  	var view *buffer.View
   274  
   275  	// Packet information.
   276  	if !d.flags.NoPacketInfo {
   277  		view = buffer.NewView(PacketInfoHeaderSize + pkt.Size())
   278  		view.Grow(PacketInfoHeaderSize)
   279  		hdr := PacketInfoHeader(view.AsSlice())
   280  		hdr.Encode(&PacketInfoFields{
   281  			Protocol: pkt.NetworkProtocolNumber,
   282  		})
   283  		pktView := pkt.ToView()
   284  		view.Write(pktView.AsSlice())
   285  		pktView.Release()
   286  	} else {
   287  		view = pkt.ToView()
   288  	}
   289  
   290  	return view
   291  }
   292  
   293  // Name returns the name of the attached network interface. Empty string if
   294  // unattached.
   295  func (d *Device) Name() string {
   296  	d.mu.RLock()
   297  	defer d.mu.RUnlock()
   298  	if d.endpoint != nil {
   299  		return d.endpoint.name
   300  	}
   301  	return ""
   302  }
   303  
   304  // Flags returns the flags set for d. Zero value if unset.
   305  func (d *Device) Flags() Flags {
   306  	d.mu.RLock()
   307  	defer d.mu.RUnlock()
   308  	return d.flags
   309  }
   310  
   311  // Readiness implements watier.Waitable.Readiness.
   312  func (d *Device) Readiness(mask waiter.EventMask) waiter.EventMask {
   313  	if mask&waiter.ReadableEvents != 0 {
   314  		d.mu.RLock()
   315  		endpoint := d.endpoint
   316  		d.mu.RUnlock()
   317  		if endpoint != nil && endpoint.NumQueued() == 0 {
   318  			mask &= ^waiter.ReadableEvents
   319  		}
   320  	}
   321  	return mask & (waiter.ReadableEvents | waiter.WritableEvents)
   322  }
   323  
   324  // WriteNotify implements channel.Notification.WriteNotify.
   325  func (d *Device) WriteNotify() {
   326  	d.Notify(waiter.ReadableEvents)
   327  }
   328  
   329  // tunEndpoint is the link endpoint for the NIC created by the tun device.
   330  //
   331  // It is ref-counted as multiple opening files can attach to the same NIC.
   332  // The last owner is responsible for deleting the NIC.
   333  type tunEndpoint struct {
   334  	tunEndpointRefs
   335  	*channel.Endpoint
   336  
   337  	stack *stack.Stack
   338  	nicID tcpip.NICID
   339  	name  string
   340  	isTap bool
   341  }
   342  
   343  // DecRef decrements refcount of e, removing NIC if it reaches 0.
   344  func (e *tunEndpoint) DecRef(ctx context.Context) {
   345  	e.tunEndpointRefs.DecRef(func() {
   346  		e.Close()
   347  		e.stack.RemoveNIC(e.nicID)
   348  	})
   349  }
   350  
   351  // ARPHardwareType implements stack.LinkEndpoint.ARPHardwareType.
   352  func (e *tunEndpoint) ARPHardwareType() header.ARPHardwareType {
   353  	if e.isTap {
   354  		return header.ARPHardwareEther
   355  	}
   356  	return header.ARPHardwareNone
   357  }
   358  
   359  // AddHeader implements stack.LinkEndpoint.AddHeader.
   360  func (e *tunEndpoint) AddHeader(pkt stack.PacketBufferPtr) {
   361  	if !e.isTap {
   362  		return
   363  	}
   364  	eth := header.Ethernet(pkt.LinkHeader().Push(header.EthernetMinimumSize))
   365  	eth.Encode(&header.EthernetFields{
   366  		SrcAddr: pkt.EgressRoute.LocalLinkAddress,
   367  		DstAddr: pkt.EgressRoute.RemoteLinkAddress,
   368  		Type:    pkt.NetworkProtocolNumber,
   369  	})
   370  }
   371  
   372  // MaxHeaderLength returns the maximum size of the link layer header.
   373  func (e *tunEndpoint) MaxHeaderLength() uint16 {
   374  	if e.isTap {
   375  		return header.EthernetMinimumSize
   376  	}
   377  	return 0
   378  }