/* * Copyright (c) 2020, Psiphon Inc. * All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /* Package packetman implements low-level manipulation of TCP packets, enabling a variety of strategies to evade network censorship. This implementation is entirely based on and is a subset of Geneva: Come as You Are: Helping Unmodified Clients Bypass Censorship with Server-side Evasion Kevin Bock, George Hughey, Louis-Henri Merino, Tania Arya, Daniel Liscinsky, Regina Pogosian, Dave Levin ACM SIGCOMM 2020 Geneva: Evolving Censorship Evasion Strategies Kevin Bock, George Hughey, Xiao Qiang, Dave Levin ACM CCS 2019 (Conference on Computer and Communications Security) https://github.com/Kkevsterrr/geneva This package implements the equivilent of the Geneva "engine", which can execute packet manipulation strategies. It does not implement the genetic algorithm component. Other notable differences: - We intercept, parse, and transform only server-side outbound SYN-ACK packets. Geneva supports client-side packet manipulation with a more diverse set of trigger packets, but in practise we cannot execute most low-level packet operations on client platforms such as Android and iOS. - For expediancy, we use a simplified strategy syntax (called transformation specs, to avoid confusion with the more general original). As we do not evolve strategies, we do not use a tree representation and some randomization tranformations are simplified. At this time, full functionality is limited to the Linux platform. Security: external parties can induce the server to emit a SYN-ACK, invoking the packet manipulation logic. External parties cannot set the transformation specs, and, as the input is the server-side generated SYN-ACK packet, cannot influence the packet manipulation with any external input parameters. */ package packetman import ( "encoding/binary" "encoding/hex" "fmt" "net" "strings" "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common" "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors" "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng" "github.com/google/gopacket" "github.com/google/gopacket/layers" ) // Config specifies a packet manipulation configuration. type Config struct { // Logger is used for logging events and metrics. Logger common.Logger // ProtocolPorts specifies the set of TCP ports to which SYN-ACK packet // interception and manipulation is to be applied. To accommodate hosts with // multiple IP addresses, packet interception is applied to all interfaces. ProtocolPorts []int // On Linux, which uses NFQUEUE and raw sockets, QueueNumber is the NFQUEUE // queue-num parameter to be used. QueueNumber int // On Linux, which uses NFQUEUE and raw sockets, SocketMark is the SO_MARK // value to be used. When 0, a default value is used. SocketMark int // Specs is the list of packet transformation Spec value that are to be // available for packet manipulation. Spec names must be unique. Specs []*Spec // SelectSpecName is a callback invoked for each intercepted SYN-ACK packet. // SelectSpecName must return a name of a Spec, in Specs, to apply that // transformation spec, or "" to send the SYN-ACK packet unmodified. // // The inputs protocolPort and clientIP allow the callback to select a Spec // based on the protocol running at the intercepted packet's port and/or // client GeoIP. SelectSpecName func(protocolPort int, clientIP net.IP) string // SudoNetworkConfigCommands specifies whether to use "sudo" when executing // network configuration commands. See comment for same parameter in // psiphon/common/tun. SudoNetworkConfigCommands bool // AllowNoIPv6NetworkConfiguration indicates that failures while configuring // tun interfaces and routing for IPv6 are to be logged as warnings only. See // comment for same parameter in psiphon/common/tun. AllowNoIPv6NetworkConfiguration bool } // Spec specifies a set of transformations to be applied to an intercepted // SYN-ACK packet to produce zero or more replacement packets to be sent in // its place. // // Each element in PacketSpecs specifies a new outgoing packet. Each element // in a packet specification specifies an individual transformation to be // applied, in turn, to a copy of the intercepted SYN-ACK packet, producing // the outgoing packet. // // Syntax of individual tranformations: // // "TCP-flags random|" // "TCP- random|" // "TCP-option-