golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/ipv4/control.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 package ipv4 6 7 import ( 8 "fmt" 9 "net" 10 "sync" 11 12 "golang.org/x/net/internal/iana" 13 "golang.org/x/net/internal/socket" 14 ) 15 16 type rawOpt struct { 17 sync.RWMutex 18 cflags ControlFlags 19 } 20 21 func (c *rawOpt) set(f ControlFlags) { c.cflags |= f } 22 func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f } 23 func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 } 24 25 type ControlFlags uint 26 27 const ( 28 FlagTTL ControlFlags = 1 << iota // pass the TTL on the received packet 29 FlagSrc // pass the source address on the received packet 30 FlagDst // pass the destination address on the received packet 31 FlagInterface // pass the interface index on the received packet 32 ) 33 34 // A ControlMessage represents per packet basis IP-level socket options. 35 type ControlMessage struct { 36 // Receiving socket options: SetControlMessage allows to 37 // receive the options from the protocol stack using ReadFrom 38 // method of PacketConn or RawConn. 39 // 40 // Specifying socket options: ControlMessage for WriteTo 41 // method of PacketConn or RawConn allows to send the options 42 // to the protocol stack. 43 // 44 TTL int // time-to-live, receiving only 45 Src net.IP // source address, specifying only 46 Dst net.IP // destination address, receiving only 47 IfIndex int // interface index, must be 1 <= value when specifying 48 } 49 50 func (cm *ControlMessage) String() string { 51 if cm == nil { 52 return "<nil>" 53 } 54 return fmt.Sprintf("ttl=%d src=%v dst=%v ifindex=%d", cm.TTL, cm.Src, cm.Dst, cm.IfIndex) 55 } 56 57 // Marshal returns the binary encoding of cm. 58 func (cm *ControlMessage) Marshal() []byte { 59 if cm == nil { 60 return nil 61 } 62 var m socket.ControlMessage 63 if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To4() != nil || cm.IfIndex > 0) { 64 m = socket.NewControlMessage([]int{ctlOpts[ctlPacketInfo].length}) 65 } 66 if len(m) > 0 { 67 ctlOpts[ctlPacketInfo].marshal(m, cm) 68 } 69 return m 70 } 71 72 // Parse parses b as a control message and stores the result in cm. 73 func (cm *ControlMessage) Parse(b []byte) error { 74 ms, err := socket.ControlMessage(b).Parse() 75 if err != nil { 76 return err 77 } 78 for _, m := range ms { 79 lvl, typ, l, err := m.ParseHeader() 80 if err != nil { 81 return err 82 } 83 if lvl != iana.ProtocolIP { 84 continue 85 } 86 switch { 87 case typ == ctlOpts[ctlTTL].name && l >= ctlOpts[ctlTTL].length: 88 ctlOpts[ctlTTL].parse(cm, m.Data(l)) 89 case typ == ctlOpts[ctlDst].name && l >= ctlOpts[ctlDst].length: 90 ctlOpts[ctlDst].parse(cm, m.Data(l)) 91 case typ == ctlOpts[ctlInterface].name && l >= ctlOpts[ctlInterface].length: 92 ctlOpts[ctlInterface].parse(cm, m.Data(l)) 93 case typ == ctlOpts[ctlPacketInfo].name && l >= ctlOpts[ctlPacketInfo].length: 94 ctlOpts[ctlPacketInfo].parse(cm, m.Data(l)) 95 } 96 } 97 return nil 98 } 99 100 // NewControlMessage returns a new control message. 101 // 102 // The returned message is large enough for options specified by cf. 103 func NewControlMessage(cf ControlFlags) []byte { 104 opt := rawOpt{cflags: cf} 105 var l int 106 if opt.isset(FlagTTL) && ctlOpts[ctlTTL].name > 0 { 107 l += socket.ControlMessageSpace(ctlOpts[ctlTTL].length) 108 } 109 if ctlOpts[ctlPacketInfo].name > 0 { 110 if opt.isset(FlagSrc | FlagDst | FlagInterface) { 111 l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length) 112 } 113 } else { 114 if opt.isset(FlagDst) && ctlOpts[ctlDst].name > 0 { 115 l += socket.ControlMessageSpace(ctlOpts[ctlDst].length) 116 } 117 if opt.isset(FlagInterface) && ctlOpts[ctlInterface].name > 0 { 118 l += socket.ControlMessageSpace(ctlOpts[ctlInterface].length) 119 } 120 } 121 var b []byte 122 if l > 0 { 123 b = make([]byte, l) 124 } 125 return b 126 } 127 128 // Ancillary data socket options 129 const ( 130 ctlTTL = iota // header field 131 ctlSrc // header field 132 ctlDst // header field 133 ctlInterface // inbound or outbound interface 134 ctlPacketInfo // inbound or outbound packet path 135 ctlMax 136 ) 137 138 // A ctlOpt represents a binding for ancillary data socket option. 139 type ctlOpt struct { 140 name int // option name, must be equal or greater than 1 141 length int // option length 142 marshal func([]byte, *ControlMessage) []byte 143 parse func(*ControlMessage, []byte) 144 }