| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package filter |
| |
| import ( |
| "encoding/binary" |
| "github.com/google/netstack/tcpip/buffer" |
| |
| "github.com/google/netstack/tcpip" |
| "github.com/google/netstack/tcpip/header" |
| ) |
| |
| // ChangePacket implements incremental checksum calculation. |
| |
| func newChecksum(oldCksum uint16, oldVal uint16, newVal uint16, udp bool) uint16 { |
| if udp && oldCksum == 0 { |
| // Checksum is not set. |
| return 0 |
| } |
| c := uint32(oldCksum) + uint32(oldVal) - uint32(newVal) |
| c = (c >> 16) + (c & 0xffff) |
| if udp && c == 0 { |
| return 0xffff |
| } else { |
| return uint16(c) |
| } |
| } |
| |
| func rewritePacketICMPv4(newAddr tcpip.Address, isSource bool, hdr buffer.Prependable, transportHeader []byte) { |
| ipv4 := header.IPv4(hdr.View()) |
| |
| var oldAddr tcpip.Address |
| if isSource { |
| oldAddr = ipv4.SourceAddress() |
| ipv4.SetSourceAddress(newAddr) |
| } else { |
| oldAddr = ipv4.DestinationAddress() |
| ipv4.SetDestinationAddress(newAddr) |
| } |
| |
| iCksum := ipv4.Checksum() |
| // icmp checksum is not affected. |
| |
| oldA := []byte(oldAddr) |
| newA := []byte(newAddr) |
| for i := 0; i < header.IPv4AddressSize; i += 2 { |
| iCksum = newChecksum(iCksum, |
| binary.BigEndian.Uint16(oldA[i:]), |
| binary.BigEndian.Uint16(newA[i:]), false) |
| } |
| |
| ipv4.SetChecksum(iCksum) |
| } |
| |
| func rewritePacketUDPv4(newAddr tcpip.Address, newPort uint16, isSource bool, hdr buffer.Prependable, transportHeader []byte) { |
| ipv4 := header.IPv4(hdr.View()) |
| |
| var oldAddr tcpip.Address |
| if isSource { |
| oldAddr = ipv4.SourceAddress() |
| ipv4.SetSourceAddress(newAddr) |
| } else { |
| oldAddr = ipv4.DestinationAddress() |
| ipv4.SetDestinationAddress(newAddr) |
| } |
| |
| iCksum := ipv4.Checksum() |
| udp := header.UDP(transportHeader) |
| tCksum := udp.Checksum() |
| |
| oldA := []byte(oldAddr) |
| newA := []byte(newAddr) |
| for i := 0; i < header.IPv4AddressSize; i += 2 { |
| iCksum = newChecksum(iCksum, |
| binary.BigEndian.Uint16(oldA[i:]), |
| binary.BigEndian.Uint16(newA[i:]), false) |
| tCksum = newChecksum(tCksum, |
| binary.BigEndian.Uint16(oldA[i:]), |
| binary.BigEndian.Uint16(newA[i:]), true) // set true for UDP |
| } |
| |
| if isSource { |
| tCksum = newChecksum(tCksum, udp.SourcePort(), newPort, true) |
| udp.SetSourcePort(newPort) |
| } else { |
| tCksum = newChecksum(tCksum, udp.DestinationPort(), newPort, true) |
| udp.SetDestinationPort(newPort) |
| } |
| |
| ipv4.SetChecksum(iCksum) |
| udp.SetChecksum(tCksum) |
| } |
| |
| func rewritePacketTCPv4(newAddr tcpip.Address, newPort uint16, isSource bool, hdr buffer.Prependable, transportHeader []byte) { |
| ipv4 := header.IPv4(hdr.View()) |
| |
| var oldAddr tcpip.Address |
| if isSource { |
| oldAddr = ipv4.SourceAddress() |
| ipv4.SetSourceAddress(newAddr) |
| } else { |
| oldAddr = ipv4.DestinationAddress() |
| ipv4.SetDestinationAddress(newAddr) |
| } |
| |
| iCksum := ipv4.Checksum() |
| tcp := header.TCP(transportHeader) |
| tCksum := tcp.Checksum() |
| |
| oldA := []byte(oldAddr) |
| newA := []byte(newAddr) |
| for i := 0; i < header.IPv4AddressSize; i += 2 { |
| iCksum = newChecksum(iCksum, |
| binary.BigEndian.Uint16(oldA[i:]), |
| binary.BigEndian.Uint16(newA[i:]), false) |
| tCksum = newChecksum(tCksum, |
| binary.BigEndian.Uint16(oldA[i:]), |
| binary.BigEndian.Uint16(newA[i:]), false) |
| } |
| |
| if isSource { |
| tCksum = newChecksum(tCksum, tcp.SourcePort(), newPort, false) |
| tcp.SetSourcePort(newPort) |
| } else { |
| tCksum = newChecksum(tCksum, tcp.DestinationPort(), newPort, false) |
| tcp.SetDestinationPort(newPort) |
| } |
| |
| ipv4.SetChecksum(iCksum) |
| tcp.SetChecksum(tCksum) |
| } |
| |
| func rewritePacketUDPv6(newAddr tcpip.Address, newPort uint16, isSource bool, hdr buffer.Prependable, transportHeader []byte) { |
| ipv6 := header.IPv6(hdr.View()) |
| |
| var oldAddr tcpip.Address |
| if isSource { |
| oldAddr = ipv6.SourceAddress() |
| ipv6.SetSourceAddress(newAddr) |
| } else { |
| oldAddr = ipv6.DestinationAddress() |
| ipv6.SetDestinationAddress(newAddr) |
| } |
| |
| udp := header.UDP(transportHeader) |
| tCksum := udp.Checksum() |
| |
| oldA := []byte(oldAddr) |
| newA := []byte(newAddr) |
| for i := 0; i < header.IPv6AddressSize; i += 2 { |
| tCksum = newChecksum(tCksum, |
| binary.BigEndian.Uint16(oldA[i:]), |
| binary.BigEndian.Uint16(newA[i:]), true) // set true for UDP |
| } |
| |
| if isSource { |
| tCksum = newChecksum(tCksum, udp.SourcePort(), newPort, true) |
| udp.SetSourcePort(newPort) |
| } else { |
| tCksum = newChecksum(tCksum, udp.DestinationPort(), newPort, true) |
| udp.SetDestinationPort(newPort) |
| } |
| |
| udp.SetChecksum(tCksum) |
| } |
| |
| func rewritePacketTCPv6(newAddr tcpip.Address, newPort uint16, isSource bool, hdr buffer.Prependable, transportHeader []byte) { |
| ipv6 := header.IPv6(hdr.View()) |
| |
| var oldAddr tcpip.Address |
| if isSource { |
| oldAddr = ipv6.SourceAddress() |
| ipv6.SetSourceAddress(newAddr) |
| } else { |
| oldAddr = ipv6.DestinationAddress() |
| ipv6.SetDestinationAddress(newAddr) |
| } |
| |
| tcp := header.TCP(transportHeader) |
| tCksum := tcp.Checksum() |
| |
| oldA := []byte(oldAddr) |
| newA := []byte(newAddr) |
| for i := 0; i < header.IPv6AddressSize; i += 2 { |
| tCksum = newChecksum(tCksum, |
| binary.BigEndian.Uint16(oldA[i:]), |
| binary.BigEndian.Uint16(newA[i:]), false) |
| } |
| |
| if isSource { |
| tCksum = newChecksum(tCksum, tcp.SourcePort(), newPort, false) |
| tcp.SetSourcePort(newPort) |
| } else { |
| tCksum = newChecksum(tCksum, tcp.DestinationPort(), newPort, false) |
| tcp.SetDestinationPort(newPort) |
| } |
| |
| tcp.SetChecksum(tCksum) |
| } |