github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/ipv4/control_unix.go (about)

     1  // Copyright 2012 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build darwin dragonfly freebsd linux netbsd openbsd
     6  
     7  package ipv4
     8  
     9  import (
    10  	"os"
    11  	"syscall"
    12  	"unsafe"
    13  
    14  	"golang.org/x/net/internal/iana"
    15  )
    16  
    17  func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
    18  	opt.Lock()
    19  	defer opt.Unlock()
    20  	if cf&FlagTTL != 0 && sockOpts[ssoReceiveTTL].name > 0 {
    21  		if err := setInt(fd, &sockOpts[ssoReceiveTTL], boolint(on)); err != nil {
    22  			return err
    23  		}
    24  		if on {
    25  			opt.set(FlagTTL)
    26  		} else {
    27  			opt.clear(FlagTTL)
    28  		}
    29  	}
    30  	if sockOpts[ssoPacketInfo].name > 0 {
    31  		if cf&(FlagSrc|FlagDst|FlagInterface) != 0 {
    32  			if err := setInt(fd, &sockOpts[ssoPacketInfo], boolint(on)); err != nil {
    33  				return err
    34  			}
    35  			if on {
    36  				opt.set(cf & (FlagSrc | FlagDst | FlagInterface))
    37  			} else {
    38  				opt.clear(cf & (FlagSrc | FlagDst | FlagInterface))
    39  			}
    40  		}
    41  	} else {
    42  		if cf&FlagDst != 0 && sockOpts[ssoReceiveDst].name > 0 {
    43  			if err := setInt(fd, &sockOpts[ssoReceiveDst], boolint(on)); err != nil {
    44  				return err
    45  			}
    46  			if on {
    47  				opt.set(FlagDst)
    48  			} else {
    49  				opt.clear(FlagDst)
    50  			}
    51  		}
    52  		if cf&FlagInterface != 0 && sockOpts[ssoReceiveInterface].name > 0 {
    53  			if err := setInt(fd, &sockOpts[ssoReceiveInterface], boolint(on)); err != nil {
    54  				return err
    55  			}
    56  			if on {
    57  				opt.set(FlagInterface)
    58  			} else {
    59  				opt.clear(FlagInterface)
    60  			}
    61  		}
    62  	}
    63  	return nil
    64  }
    65  
    66  func newControlMessage(opt *rawOpt) (oob []byte) {
    67  	opt.RLock()
    68  	var l int
    69  	if opt.isset(FlagTTL) && ctlOpts[ctlTTL].name > 0 {
    70  		l += syscall.CmsgSpace(ctlOpts[ctlTTL].length)
    71  	}
    72  	if ctlOpts[ctlPacketInfo].name > 0 {
    73  		if opt.isset(FlagSrc | FlagDst | FlagInterface) {
    74  			l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
    75  		}
    76  	} else {
    77  		if opt.isset(FlagDst) && ctlOpts[ctlDst].name > 0 {
    78  			l += syscall.CmsgSpace(ctlOpts[ctlDst].length)
    79  		}
    80  		if opt.isset(FlagInterface) && ctlOpts[ctlInterface].name > 0 {
    81  			l += syscall.CmsgSpace(ctlOpts[ctlInterface].length)
    82  		}
    83  	}
    84  	if l > 0 {
    85  		oob = make([]byte, l)
    86  		b := oob
    87  		if opt.isset(FlagTTL) && ctlOpts[ctlTTL].name > 0 {
    88  			b = ctlOpts[ctlTTL].marshal(b, nil)
    89  		}
    90  		if ctlOpts[ctlPacketInfo].name > 0 {
    91  			if opt.isset(FlagSrc | FlagDst | FlagInterface) {
    92  				b = ctlOpts[ctlPacketInfo].marshal(b, nil)
    93  			}
    94  		} else {
    95  			if opt.isset(FlagDst) && ctlOpts[ctlDst].name > 0 {
    96  				b = ctlOpts[ctlDst].marshal(b, nil)
    97  			}
    98  			if opt.isset(FlagInterface) && ctlOpts[ctlInterface].name > 0 {
    99  				b = ctlOpts[ctlInterface].marshal(b, nil)
   100  			}
   101  		}
   102  	}
   103  	opt.RUnlock()
   104  	return
   105  }
   106  
   107  func parseControlMessage(b []byte) (*ControlMessage, error) {
   108  	if len(b) == 0 {
   109  		return nil, nil
   110  	}
   111  	cmsgs, err := syscall.ParseSocketControlMessage(b)
   112  	if err != nil {
   113  		return nil, os.NewSyscallError("parse socket control message", err)
   114  	}
   115  	cm := &ControlMessage{}
   116  	for _, m := range cmsgs {
   117  		if m.Header.Level != iana.ProtocolIP {
   118  			continue
   119  		}
   120  		switch int(m.Header.Type) {
   121  		case ctlOpts[ctlTTL].name:
   122  			ctlOpts[ctlTTL].parse(cm, m.Data[:])
   123  		case ctlOpts[ctlDst].name:
   124  			ctlOpts[ctlDst].parse(cm, m.Data[:])
   125  		case ctlOpts[ctlInterface].name:
   126  			ctlOpts[ctlInterface].parse(cm, m.Data[:])
   127  		case ctlOpts[ctlPacketInfo].name:
   128  			ctlOpts[ctlPacketInfo].parse(cm, m.Data[:])
   129  		}
   130  	}
   131  	return cm, nil
   132  }
   133  
   134  func marshalControlMessage(cm *ControlMessage) (oob []byte) {
   135  	if cm == nil {
   136  		return nil
   137  	}
   138  	var l int
   139  	pktinfo := false
   140  	if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To4() != nil || cm.IfIndex > 0) {
   141  		pktinfo = true
   142  		l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
   143  	}
   144  	if l > 0 {
   145  		oob = make([]byte, l)
   146  		b := oob
   147  		if pktinfo {
   148  			b = ctlOpts[ctlPacketInfo].marshal(b, cm)
   149  		}
   150  	}
   151  	return
   152  }
   153  
   154  func marshalTTL(b []byte, cm *ControlMessage) []byte {
   155  	m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
   156  	m.Level = iana.ProtocolIP
   157  	m.Type = sysIP_RECVTTL
   158  	m.SetLen(syscall.CmsgLen(1))
   159  	return b[syscall.CmsgSpace(1):]
   160  }
   161  
   162  func parseTTL(cm *ControlMessage, b []byte) {
   163  	cm.TTL = int(*(*byte)(unsafe.Pointer(&b[:1][0])))
   164  }