From 8b012941c1960a7be64fb390d0df3383c67b98ce Mon Sep 17 00:00:00 2001 From: Elazar Gershuni Date: Tue, 12 Mar 2024 15:40:41 +0200 Subject: [PATCH] protocols package Signed-off-by: Elazar Gershuni --- pkg/netp/common.go | 20 +++++++ pkg/netp/icmp.go | 128 +++++++++++++++++++++++++++++++++++++++++++++ pkg/netp/tcpudp.go | 35 +++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 pkg/netp/common.go create mode 100644 pkg/netp/icmp.go create mode 100644 pkg/netp/tcpudp.go diff --git a/pkg/netp/common.go b/pkg/netp/common.go new file mode 100644 index 0000000..abd2b31 --- /dev/null +++ b/pkg/netp/common.go @@ -0,0 +1,20 @@ +// Copyright 2020- IBM Inc. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package netp + +type Protocol interface { + // InverseDirection returns the response expected for a request made using this protocol + InverseDirection() Protocol +} + +type AnyProtocol struct{} + +func (t AnyProtocol) InverseDirection() Protocol { return AnyProtocol{} } + +type ProtocolString string + +const ( + ProtocolStringTCP ProtocolString = "TCP" + ProtocolStringUDP ProtocolString = "UDP" + ProtocolStringICMP ProtocolString = "ICMP" +) diff --git a/pkg/netp/icmp.go b/pkg/netp/icmp.go new file mode 100644 index 0000000..f976adc --- /dev/null +++ b/pkg/netp/icmp.go @@ -0,0 +1,128 @@ +// Copyright 2020- IBM Inc. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package netp + +import ( + "fmt" + "log" +) + +type ICMPTypeCode struct { + // ICMP type allowed. + Type int + + // ICMP code allowed. If omitted, any code is allowed + Code *int +} + +type ICMP struct { + typeCode *ICMPTypeCode +} + +func NewICMP(typeCode *ICMPTypeCode) (ICMP, error) { + err := ValidateICMP(typeCode) + if err != nil { + return ICMP{}, err + } + return ICMP{typeCode: typeCode}, nil +} + +func (t ICMP) ICMPTypeCode() *ICMPTypeCode { + if t.typeCode == nil { + return nil + } + if t.typeCode.Code == nil { + return t.typeCode + } + // avoid aliasing and mutation by someone else + code := *t.typeCode.Code + return &ICMPTypeCode{Type: t.typeCode.Type, Code: &code} +} + +func (t ICMP) InverseDirection() Protocol { + if t.typeCode == nil { + return nil + } + + if invType := inverseICMPType(t.typeCode.Type); invType != undefinedICMP { + return ICMP{typeCode: &ICMPTypeCode{Type: invType, Code: t.typeCode.Code}} + } + return nil +} + +// Based on https://datatracker.ietf.org/doc/html/rfc792 + +const ( + EchoReply = 0 + DestinationUnreachable = 3 + SourceQuench = 4 + Redirect = 5 + Echo = 8 + TimeExceeded = 11 + ParameterProblem = 12 + Timestamp = 13 + TimestampReply = 14 + InformationRequest = 15 + InformationReply = 16 + + undefinedICMP = -2 +) + +// inverseICMPType returns the reply type for request type and vice versa. +// When there is no inverse, returns undefinedICMP +func inverseICMPType(t int) int { + switch t { + case Echo: + return EchoReply + case EchoReply: + return Echo + + case Timestamp: + return TimestampReply + case TimestampReply: + return Timestamp + + case InformationRequest: + return InformationReply + case InformationReply: + return InformationRequest + + case DestinationUnreachable, SourceQuench, Redirect, TimeExceeded, ParameterProblem: + return undefinedICMP + default: + log.Panicf("Impossible ICMP type: %v", t) + } + return undefinedICMP +} + +//nolint:revive // magic numbers are fine here +func ValidateICMP(typeCode *ICMPTypeCode) error { + if typeCode == nil { + return nil + } + maxCodes := map[int]int{ + EchoReply: 0, + DestinationUnreachable: 5, + SourceQuench: 0, + Redirect: 3, + Echo: 0, + TimeExceeded: 1, + ParameterProblem: 0, + Timestamp: 0, + TimestampReply: 0, + InformationRequest: 0, + InformationReply: 0, + } + maxCode, ok := maxCodes[typeCode.Type] + if !ok { + return fmt.Errorf("invalid ICMP type %v", typeCode.Type) + } + if *typeCode.Code > maxCode { + return fmt.Errorf("ICMP code %v is invalid for ICMP type %v", *typeCode.Code, typeCode.Type) + } + return nil +} + +func (t ICMP) ProtocolString() ProtocolString { + return ProtocolStringICMP +} diff --git a/pkg/netp/tcpudp.go b/pkg/netp/tcpudp.go new file mode 100644 index 0000000..29e5c5d --- /dev/null +++ b/pkg/netp/tcpudp.go @@ -0,0 +1,35 @@ +// Copyright 2020- IBM Inc. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +package netp + +import "github.com/np-guard/models/pkg/interval" + +const MinPort = 1 +const MaxPort = 65535 + +type PortRangePair struct { + SrcPort interval.Interval + DstPort interval.Interval +} + +type TCPUDP struct { + IsTCP bool + PortRangePair PortRangePair +} + +func (t TCPUDP) InverseDirection() Protocol { + if !t.IsTCP { + return nil + } + return TCPUDP{ + IsTCP: true, + PortRangePair: PortRangePair{SrcPort: t.PortRangePair.DstPort, DstPort: t.PortRangePair.SrcPort}, + } +} + +func (t TCPUDP) ProtocolString() ProtocolString { + if t.IsTCP { + return ProtocolStringTCP + } + return ProtocolStringUDP +}