github.com/psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/parameters/packetman.go (about)

     1  /*
     2   * Copyright (c) 2020, Psiphon Inc.
     3   * All rights reserved.
     4   *
     5   * This program is free software: you can redistribute it and/or modify
     6   * it under the terms of the GNU General Public License as published by
     7   * the Free Software Foundation, either version 3 of the License, or
     8   * (at your option) any later version.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package parameters
    21  
    22  import (
    23  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
    24  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
    25  )
    26  
    27  // PacketManipulationSpec is a work-around to avoid the client-side code size
    28  // impact of importing the packetman package and its dependencies.
    29  //
    30  // TODO: Given that packetman and its parameters are server-side only,
    31  // rearrange tactics/parameters to reference packetman.Spec directly, but only
    32  // in server code. This should allow reinstating the spec.Validate below.
    33  
    34  // PacketManipulationSpec is type-compatible with
    35  // psiphon/common.packetman.Spec.
    36  type PacketManipulationSpec struct {
    37  	Name        string
    38  	PacketSpecs [][]string
    39  }
    40  
    41  // PacketManipulationSpecs is a list of packet manipulation specs.
    42  type PacketManipulationSpecs []*PacketManipulationSpec
    43  
    44  // Validate checks that each spec name is unique and that each spec compiles.
    45  func (specs PacketManipulationSpecs) Validate() error {
    46  	specNames := make(map[string]bool)
    47  	for _, spec := range specs {
    48  		if spec.Name == "" {
    49  			return errors.TraceNew("missing spec name")
    50  		}
    51  		if ok, _ := specNames[spec.Name]; ok {
    52  			return errors.Tracef("duplicate spec name: %s", spec.Name)
    53  		}
    54  		specNames[spec.Name] = true
    55  
    56  		// See PacketManipulationSpec comment above.
    57  		//
    58  		// Note that, even with spec.Validate disabled, spec validation will still
    59  		// be performed, by packetman.Manipulator, on startup and after tactics hot
    60  		// reload, with equivilent outcomes for invalid specs; however, the tactics
    61  		// load itself will not fail in this case.
    62  
    63  		// err := spec.Validate()
    64  		// if err != nil {
    65  		// 	return errors.Trace(err)
    66  		// }
    67  	}
    68  	return nil
    69  }
    70  
    71  // ProtocolPacketManipulations is a map from tunnel protocol names (or "All")
    72  // to a list of packet manipulation spec names.
    73  type ProtocolPacketManipulations map[string][]string
    74  
    75  // Validate checks that tunnel protocol and spec names are valid. Duplicate
    76  // spec names are allowed in each entry, enabling weighted selection.
    77  func (manipulations ProtocolPacketManipulations) Validate(specs PacketManipulationSpecs) error {
    78  	validSpecNames := make(map[string]bool)
    79  	for _, spec := range specs {
    80  		validSpecNames[spec.Name] = true
    81  	}
    82  	for tunnelProtocol, specNames := range manipulations {
    83  		if tunnelProtocol != protocol.TUNNEL_PROTOCOLS_ALL {
    84  			if !protocol.TunnelProtocolMayUseServerPacketManipulation(tunnelProtocol) {
    85  				return errors.TraceNew("invalid tunnel protocol for packet manipulation")
    86  			}
    87  		}
    88  
    89  		for _, specName := range specNames {
    90  			if ok, _ := validSpecNames[specName]; !ok {
    91  				return errors.Tracef("invalid spec name: %s", specName)
    92  			}
    93  		}
    94  	}
    95  	return nil
    96  }