github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/stack/iptables_targets.go (about) 1 // Copyright 2019 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 stack 16 17 import ( 18 "fmt" 19 20 "github.com/SagerNet/gvisor/pkg/log" 21 "github.com/SagerNet/gvisor/pkg/tcpip" 22 "github.com/SagerNet/gvisor/pkg/tcpip/header" 23 ) 24 25 // AcceptTarget accepts packets. 26 type AcceptTarget struct { 27 // NetworkProtocol is the network protocol the target is used with. 28 NetworkProtocol tcpip.NetworkProtocolNumber 29 } 30 31 // Action implements Target.Action. 32 func (*AcceptTarget) Action(*PacketBuffer, *ConnTrack, Hook, *Route, tcpip.Address) (RuleVerdict, int) { 33 return RuleAccept, 0 34 } 35 36 // DropTarget drops packets. 37 type DropTarget struct { 38 // NetworkProtocol is the network protocol the target is used with. 39 NetworkProtocol tcpip.NetworkProtocolNumber 40 } 41 42 // Action implements Target.Action. 43 func (*DropTarget) Action(*PacketBuffer, *ConnTrack, Hook, *Route, tcpip.Address) (RuleVerdict, int) { 44 return RuleDrop, 0 45 } 46 47 // ErrorTarget logs an error and drops the packet. It represents a target that 48 // should be unreachable. 49 type ErrorTarget struct { 50 // NetworkProtocol is the network protocol the target is used with. 51 NetworkProtocol tcpip.NetworkProtocolNumber 52 } 53 54 // Action implements Target.Action. 55 func (*ErrorTarget) Action(*PacketBuffer, *ConnTrack, Hook, *Route, tcpip.Address) (RuleVerdict, int) { 56 log.Debugf("ErrorTarget triggered.") 57 return RuleDrop, 0 58 } 59 60 // UserChainTarget marks a rule as the beginning of a user chain. 61 type UserChainTarget struct { 62 // Name is the chain name. 63 Name string 64 65 // NetworkProtocol is the network protocol the target is used with. 66 NetworkProtocol tcpip.NetworkProtocolNumber 67 } 68 69 // Action implements Target.Action. 70 func (*UserChainTarget) Action(*PacketBuffer, *ConnTrack, Hook, *Route, tcpip.Address) (RuleVerdict, int) { 71 panic("UserChainTarget should never be called.") 72 } 73 74 // ReturnTarget returns from the current chain. If the chain is a built-in, the 75 // hook's underflow should be called. 76 type ReturnTarget struct { 77 // NetworkProtocol is the network protocol the target is used with. 78 NetworkProtocol tcpip.NetworkProtocolNumber 79 } 80 81 // Action implements Target.Action. 82 func (*ReturnTarget) Action(*PacketBuffer, *ConnTrack, Hook, *Route, tcpip.Address) (RuleVerdict, int) { 83 return RuleReturn, 0 84 } 85 86 // RedirectTarget redirects the packet to this machine by modifying the 87 // destination port/IP. Outgoing packets are redirected to the loopback device, 88 // and incoming packets are redirected to the incoming interface (rather than 89 // forwarded). 90 type RedirectTarget struct { 91 // Port indicates port used to redirect. It is immutable. 92 Port uint16 93 94 // NetworkProtocol is the network protocol the target is used with. It 95 // is immutable. 96 NetworkProtocol tcpip.NetworkProtocolNumber 97 } 98 99 // Action implements Target.Action. 100 func (rt *RedirectTarget) Action(pkt *PacketBuffer, ct *ConnTrack, hook Hook, r *Route, address tcpip.Address) (RuleVerdict, int) { 101 // Sanity check. 102 if rt.NetworkProtocol != pkt.NetworkProtocolNumber { 103 panic(fmt.Sprintf( 104 "RedirectTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d", 105 rt.NetworkProtocol, pkt.NetworkProtocolNumber)) 106 } 107 108 // Packet is already manipulated. 109 if pkt.NatDone { 110 return RuleAccept, 0 111 } 112 113 // Drop the packet if network and transport header are not set. 114 if pkt.NetworkHeader().View().IsEmpty() || pkt.TransportHeader().View().IsEmpty() { 115 return RuleDrop, 0 116 } 117 118 // Change the address to loopback (127.0.0.1 or ::1) in Output and to 119 // the primary address of the incoming interface in Prerouting. 120 switch hook { 121 case Output: 122 if pkt.NetworkProtocolNumber == header.IPv4ProtocolNumber { 123 address = tcpip.Address([]byte{127, 0, 0, 1}) 124 } else { 125 address = header.IPv6Loopback 126 } 127 case Prerouting: 128 // No-op, as address is already set correctly. 129 default: 130 panic("redirect target is supported only on output and prerouting hooks") 131 } 132 133 switch protocol := pkt.TransportProtocolNumber; protocol { 134 case header.UDPProtocolNumber: 135 udpHeader := header.UDP(pkt.TransportHeader().View()) 136 137 if hook == Output { 138 // Only calculate the checksum if offloading isn't supported. 139 requiresChecksum := r.RequiresTXTransportChecksum() 140 rewritePacket( 141 pkt.Network(), 142 udpHeader, 143 false, /* updateSRCFields */ 144 requiresChecksum, 145 requiresChecksum, 146 rt.Port, 147 address, 148 ) 149 } else { 150 udpHeader.SetDestinationPort(rt.Port) 151 } 152 153 pkt.NatDone = true 154 case header.TCPProtocolNumber: 155 if ct == nil { 156 return RuleAccept, 0 157 } 158 159 // Set up conection for matching NAT rule. Only the first 160 // packet of the connection comes here. Other packets will be 161 // manipulated in connection tracking. 162 if conn := ct.insertRedirectConn(pkt, hook, rt.Port, address); conn != nil { 163 ct.handlePacket(pkt, hook, r) 164 } 165 default: 166 return RuleDrop, 0 167 } 168 169 return RuleAccept, 0 170 } 171 172 // SNATTarget modifies the source port/IP in the outgoing packets. 173 type SNATTarget struct { 174 Addr tcpip.Address 175 Port uint16 176 177 // NetworkProtocol is the network protocol the target is used with. It 178 // is immutable. 179 NetworkProtocol tcpip.NetworkProtocolNumber 180 } 181 182 // Action implements Target.Action. 183 func (st *SNATTarget) Action(pkt *PacketBuffer, ct *ConnTrack, hook Hook, r *Route, address tcpip.Address) (RuleVerdict, int) { 184 // Sanity check. 185 if st.NetworkProtocol != pkt.NetworkProtocolNumber { 186 panic(fmt.Sprintf( 187 "SNATTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d", 188 st.NetworkProtocol, pkt.NetworkProtocolNumber)) 189 } 190 191 // Packet is already manipulated. 192 if pkt.NatDone { 193 return RuleAccept, 0 194 } 195 196 // Drop the packet if network and transport header are not set. 197 if pkt.NetworkHeader().View().IsEmpty() || pkt.TransportHeader().View().IsEmpty() { 198 return RuleDrop, 0 199 } 200 201 switch hook { 202 case Postrouting, Input: 203 case Prerouting, Output, Forward: 204 panic(fmt.Sprintf("%s not supported", hook)) 205 default: 206 panic(fmt.Sprintf("%s unrecognized", hook)) 207 } 208 209 switch protocol := pkt.TransportProtocolNumber; protocol { 210 case header.UDPProtocolNumber: 211 // Only calculate the checksum if offloading isn't supported. 212 requiresChecksum := r.RequiresTXTransportChecksum() 213 rewritePacket( 214 pkt.Network(), 215 header.UDP(pkt.TransportHeader().View()), 216 true, /* updateSRCFields */ 217 requiresChecksum, 218 requiresChecksum, 219 st.Port, 220 st.Addr, 221 ) 222 223 pkt.NatDone = true 224 case header.TCPProtocolNumber: 225 if ct == nil { 226 return RuleAccept, 0 227 } 228 229 // Set up conection for matching NAT rule. Only the first 230 // packet of the connection comes here. Other packets will be 231 // manipulated in connection tracking. 232 if conn := ct.insertSNATConn(pkt, hook, st.Port, st.Addr); conn != nil { 233 ct.handlePacket(pkt, hook, r) 234 } 235 default: 236 return RuleDrop, 0 237 } 238 239 return RuleAccept, 0 240 } 241 242 func rewritePacket(n header.Network, t header.ChecksummableTransport, updateSRCFields, fullChecksum, updatePseudoHeader bool, newPort uint16, newAddr tcpip.Address) { 243 if updateSRCFields { 244 if fullChecksum { 245 t.SetSourcePortWithChecksumUpdate(newPort) 246 } else { 247 t.SetSourcePort(newPort) 248 } 249 } else { 250 if fullChecksum { 251 t.SetDestinationPortWithChecksumUpdate(newPort) 252 } else { 253 t.SetDestinationPort(newPort) 254 } 255 } 256 257 if updatePseudoHeader { 258 var oldAddr tcpip.Address 259 if updateSRCFields { 260 oldAddr = n.SourceAddress() 261 } else { 262 oldAddr = n.DestinationAddress() 263 } 264 265 t.UpdateChecksumPseudoHeaderAddress(oldAddr, newAddr, fullChecksum) 266 } 267 268 if checksummableNetHeader, ok := n.(header.ChecksummableNetwork); ok { 269 if updateSRCFields { 270 checksummableNetHeader.SetSourceAddressWithChecksumUpdate(newAddr) 271 } else { 272 checksummableNetHeader.SetDestinationAddressWithChecksumUpdate(newAddr) 273 } 274 } else if updateSRCFields { 275 n.SetSourceAddress(newAddr) 276 } else { 277 n.SetDestinationAddress(newAddr) 278 } 279 }