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 }