Skip to content

Commit

Permalink
added basic tls sniffing
Browse files Browse the repository at this point in the history
  • Loading branch information
superstes committed Sep 27, 2023
1 parent 7ed7d11 commit a53a93b
Show file tree
Hide file tree
Showing 18 changed files with 380 additions and 214 deletions.
8 changes: 5 additions & 3 deletions README.md
Expand Up @@ -43,11 +43,13 @@ Its focus is set on security filtering for HTTPS.
- [ ] Filtering

- [x] TCP
- [ ] TLS
- [ ] HTTP
- [x] TLS

- [ ] Certificate validation

- [x] HTTP
- [ ] UDP

- [ ] Certificate validation
- [ ] Matches

- [x] Config
Expand Down
8 changes: 4 additions & 4 deletions config_example.yml
Expand Up @@ -13,10 +13,10 @@ service:

debug: true
timeout:
connection: 5
handshake: 5
dial: 5
intercept: 2
connection: 2000
handshake: 2000
dial: 2000
intercept: 500

output:
fwmark: 0
Expand Down
10 changes: 5 additions & 5 deletions docs/source/info/getting_started.rst
Expand Up @@ -117,11 +117,11 @@ Basic config example:
transparent: false # tproxy mode
debug: false
timeout:
connection: 5
handshake: 5
dial: 5
intercept: 2
timeout: # ms
connection: 2000
handshake: 2000
dial: 2000
intercept: 500
output:
fwmark: 0
Expand Down
90 changes: 14 additions & 76 deletions lib/cnf/cnf_file/rules_parse.go
Expand Up @@ -22,9 +22,9 @@ func ParseRules(rawRules []cnf.RuleRaw) (rules []cnf.Rule) {
for i := range rawRules {
ruleRaw := rawRules[i]
rule := cnf.Rule{
Action: filterAction(ruleRaw.Action),
Action: meta.RuleAction(ruleRaw.Action),
}
rule.Match.Encrypted = matchEncrypted(ruleRaw.Match.Encypted)
rule.Match.Encrypted = meta.MatchEncrypted(ruleRaw.Match.Encypted)

// source networks
if len(ruleRaw.Match.SrcNet) > 0 {
Expand Down Expand Up @@ -137,16 +137,16 @@ func ParseRules(rawRules []cnf.RuleRaw) (rules []cnf.Rule) {
if vf {
for i3 := range v.Value {
if vn {
rule.Match.ProtoL3N = append(rule.Match.ProtoL3N, matchProtoL3(v.Value[i3]))
rule.Match.ProtoL3N = append(rule.Match.ProtoL3N, meta.MatchProtoL3(v.Value[i3]))
} else {
rule.Match.ProtoL3 = append(rule.Match.ProtoL3, matchProtoL3(v.Value[i3]))
rule.Match.ProtoL3 = append(rule.Match.ProtoL3, meta.MatchProtoL3(v.Value[i3]))
}
}
} else {
if negate(value) {
rule.Match.ProtoL3N = append(rule.Match.ProtoL3N, matchProtoL3(value))
rule.Match.ProtoL3N = append(rule.Match.ProtoL3N, meta.MatchProtoL3(value))
} else {
rule.Match.ProtoL3 = append(rule.Match.ProtoL3, matchProtoL3(value))
rule.Match.ProtoL3 = append(rule.Match.ProtoL3, meta.MatchProtoL3(value))
}
}
}
Expand All @@ -162,16 +162,16 @@ func ParseRules(rawRules []cnf.RuleRaw) (rules []cnf.Rule) {
if vf {
for i3 := range v.Value {
if vn {
rule.Match.ProtoL4N = append(rule.Match.ProtoL4N, matchProtoL4(v.Value[i3]))
rule.Match.ProtoL4N = append(rule.Match.ProtoL4N, meta.MatchProtoL4(v.Value[i3]))
} else {
rule.Match.ProtoL4 = append(rule.Match.ProtoL4, matchProtoL4(v.Value[i3]))
rule.Match.ProtoL4 = append(rule.Match.ProtoL4, meta.MatchProtoL4(v.Value[i3]))
}
}
} else {
if negate(value) {
rule.Match.ProtoL4N = append(rule.Match.ProtoL4N, matchProtoL4(value))
rule.Match.ProtoL4N = append(rule.Match.ProtoL4N, meta.MatchProtoL4(value))
} else {
rule.Match.ProtoL4 = append(rule.Match.ProtoL4, matchProtoL4(value))
rule.Match.ProtoL4 = append(rule.Match.ProtoL4, meta.MatchProtoL4(value))
}
}
}
Expand All @@ -187,16 +187,16 @@ func ParseRules(rawRules []cnf.RuleRaw) (rules []cnf.Rule) {
if vf {
for i3 := range v.Value {
if vn {
rule.Match.ProtoL5N = append(rule.Match.ProtoL5N, matchProtoL5(v.Value[i3]))
rule.Match.ProtoL5N = append(rule.Match.ProtoL5N, meta.MatchProtoL5(v.Value[i3]))
} else {
rule.Match.ProtoL5 = append(rule.Match.ProtoL5, matchProtoL5(v.Value[i3]))
rule.Match.ProtoL5 = append(rule.Match.ProtoL5, meta.MatchProtoL5(v.Value[i3]))
}
}
} else {
if negate(value) {
rule.Match.ProtoL5N = append(rule.Match.ProtoL5N, matchProtoL5(value))
rule.Match.ProtoL5N = append(rule.Match.ProtoL5N, meta.MatchProtoL5(value))
} else {
rule.Match.ProtoL5 = append(rule.Match.ProtoL5, matchProtoL5(value))
rule.Match.ProtoL5 = append(rule.Match.ProtoL5, meta.MatchProtoL5(value))
}
}
}
Expand Down Expand Up @@ -293,68 +293,6 @@ func cleanRaw(configRaw string) (configClean string) {
return
}

func matchEncrypted(configEncrypted string) meta.OptBool {
switch strings.ToLower(configEncrypted) {
case "true", "yes", "y", "1":
return meta.OptBoolTrue
case "false", "no", "n", "0":
return meta.OptBoolFalse
default:
return meta.OptBoolNone
}
}

func filterAction(configAction string) meta.Action {
switch strings.ToLower(configAction) {
case "accept", "allow":
return meta.ActionAccept
default:
return meta.ActionDeny
}
}

func matchProtoL3(configProto string) meta.Proto {
configProto = cleanRaw(configProto)
switch strings.ToLower(configProto) {
case "ip4", "ipv4":
return meta.ProtoL3IP4
case "ip6", "ipv6":
return meta.ProtoL3IP6
default:
panic(fmt.Sprintf("protoL3 '%v' not found", configProto))
}
}

func matchProtoL4(configProto string) meta.Proto {
configProto = cleanRaw(configProto)
switch strings.ToLower(configProto) {
case "tcp":
return meta.ProtoL4Tcp
case "udp":
return meta.ProtoL4Udp
default:
panic(fmt.Sprintf("protoL4 '%v' not found or not yet supported", configProto))
}
}

func matchProtoL5(configProto string) meta.Proto {
configProto = cleanRaw(configProto)
switch strings.ToLower(configProto) {
case "tls":
return meta.ProtoL5Tls
case "http":
return meta.ProtoL5Http
/*
case "dns":
return meta.ProtoL5Dns
case "ntp":
return meta.ProtoL5Ntp
*/
default:
panic(fmt.Sprintf("protoL5 '%v' not found or not yet supported", configProto))
}
}

func matchNet(ip string) *net.IPNet {
ip = cleanRaw(ip)
// todo: allow users to provide single ip or list
Expand Down
73 changes: 1 addition & 72 deletions lib/cnf/cnf_file/rules_parse_test.go
Expand Up @@ -17,81 +17,10 @@ func TestCleanRaw(t *testing.T) {
}
}

func TestMatchFilterAction(t *testing.T) {
if filterAction("allow") != meta.ActionAccept || filterAction("accept") != meta.ActionAccept {
t.Error("Filter action accept")
}
if filterAction("deny") != meta.ActionDeny || filterAction("random") != meta.ActionDeny {
t.Error("Filter action deny")
}
}

func TestMatchEncryption(t *testing.T) {
if matchEncrypted(cnf.RuleRaw{}.Match.Encypted) != meta.OptBoolNone {
if meta.MatchEncrypted(cnf.RuleRaw{}.Match.Encypted) != meta.OptBoolNone {
t.Error("Match encryption default-none")
}
if matchEncrypted("true") != meta.OptBoolTrue || matchEncrypted("Yes") != meta.OptBoolTrue || matchEncrypted("1") != meta.OptBoolTrue {
t.Error("Match encryption true")
}
if matchEncrypted("false") != meta.OptBoolFalse || matchEncrypted("No") != meta.OptBoolFalse || matchEncrypted("0") != meta.OptBoolFalse {
t.Error("Match encryption false")
}
if matchEncrypted("random") != meta.OptBoolNone || matchEncrypted("") != meta.OptBoolNone {
t.Error("Match encryption none")
}
}

func TestMatchProtoL3(t *testing.T) {
if matchProtoL3("ip4") != meta.ProtoL3IP4 || matchProtoL3("ipv4") != meta.ProtoL3IP4 || matchProtoL3("IPv4") != meta.ProtoL3IP4 {
t.Error("Match proto L3 ip4")
}
if matchProtoL3("ip6") != meta.ProtoL3IP6 || matchProtoL3("ipv6") != meta.ProtoL3IP6 || matchProtoL3("IPv6") != meta.ProtoL3IP6 {
t.Error("Match proto L3 ip6")
}
defer func() {
if r := recover(); r == nil {
t.Errorf("Match proto L3 not failing on invalid value")
}
}()
matchProtoL3("random")
}

func TestMatchProtoL4(t *testing.T) {
if matchProtoL4("tcp") != meta.ProtoL4Tcp || matchProtoL4("TCP") != meta.ProtoL4Tcp {
t.Error("Match proto L4 tcp")
}
if matchProtoL4("udp") != meta.ProtoL4Udp || matchProtoL4("UDP") != meta.ProtoL4Udp {
t.Error("Match proto L4 udp")
}
defer func() {
if r := recover(); r == nil {
t.Errorf("Match proto L4 not failing on invalid value")
}
}()
matchProtoL4("random")
}

func TestMatchProtoL5(t *testing.T) {
if matchProtoL5("tls") != meta.ProtoL5Tls {
t.Error("Match proto L5 tls")
}
if matchProtoL5("http") != meta.ProtoL5Http {
t.Error("Match proto L5 http")
}
/*
if matchProtoL5("dns") != meta.ProtoL5Dns {
t.Error("Match proto L5 dns")
}
if matchProtoL5("ntp") != meta.ProtoL5Ntp {
t.Error("Match proto L5 ntp")
}
*/
defer func() {
if r := recover(); r == nil {
t.Errorf("Match proto L5 not failing on invalid value")
}
}()
matchProtoL5("random")
}

func TestMatchNet(t *testing.T) {
Expand Down
8 changes: 4 additions & 4 deletions lib/cnf/config.go
Expand Up @@ -29,10 +29,10 @@ type ServiceConfigListen struct {
}

type ServiceConfigTimeout struct {
Connection int `yaml:"connection" default="5"`
Handshake int `yaml:"handshake" default="5"`
Dial int `yaml:"dial" default="5"`
Intercept int `yaml:"intercept" default="2"`
Connection int `yaml:"connection" default="2000"`
Handshake int `yaml:"handshake" default="2000"`
Dial int `yaml:"dial" default="2000"`
Intercept int `yaml:"intercept" default="500"`
}

type ServiceConfigOutput struct {
Expand Down
1 change: 1 addition & 0 deletions lib/cnf/hardcoded.go
Expand Up @@ -9,6 +9,7 @@ const (
LOG_TIME_FORMAT string = "2006-01-02 15:04:05"
UDP_TTL = 30 * time.Second
UDP_BUFFER_SIZE int = 4096
L5HDRLEN int = 5
)

var ConfigFileAbs string = "/etc/calamary/config.yml"
14 changes: 1 addition & 13 deletions lib/proc/filter/main.go
Expand Up @@ -30,7 +30,7 @@ func Filter(pkt parse.ParsedPacket) bool {
continue
}

ruleDebug(pkt, rid, fmt.Sprintf("Applying action '%v'", reverseFilterAction(rule.Action)))
ruleDebug(pkt, rid, fmt.Sprintf("Applying action '%v'", meta.RevRuleAction(rule.Action)))
return applyAction(rule.Action)

}
Expand All @@ -52,15 +52,3 @@ func applyAction(action meta.Action) bool {
}
return false
}

func reverseFilterAction(action meta.Action) string {
// todo: merge with config-parser function to keep action matching in one place
switch action {
case meta.ActionAccept:
return "accept"
case meta.ActionDeny:
return "deny"
default:
return "unknown"
}
}
4 changes: 3 additions & 1 deletion lib/proc/fwd/main.go
@@ -1,6 +1,7 @@
package fwd

import (
"io"
"net"

"github.com/superstes/calamary/log"
Expand All @@ -9,7 +10,8 @@ import (
)

func Forward(l4Proto string, conn net.Conn) {
pkt := parse.Parse(l4Proto, conn)
var connIo io.ReadWriter = conn
pkt := parse.Parse(l4Proto, conn, connIo)
if filter.Filter(pkt) {
// dialer := nw.NewDialerDirect()
log.ConnInfo(
Expand Down

0 comments on commit a53a93b

Please sign in to comment.