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 }