diff --git a/Makefile b/Makefile index 3e9968b..6579b2f 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ copier: echo 'for f in $$(ls); do scp $$f/*.deb user@192.168.99.106:~/DEBIAN_PKGS/$$f/main/; done' >> deb/copy.sh fmt: - find . -name '*.go' -exec gofmt -w -s {} \; + find . -name '*.go' -exec gofumpt -w -s -extra {} \; upload-linux: github-release upload -R -u $(USER_GH) -r "$(packagename)" -t $(VERSION) -l `sha256sum ` -n "$(packagename)" -f "$(packagename)" diff --git a/config.go b/config.go index 5098efb..acd30e9 100644 --- a/config.go +++ b/config.go @@ -43,7 +43,7 @@ func (f *I2PConfig) Sam() string { "host": host, "port": port, }).Debug("SAM address constructed") - return host + ":" + port + return fmt.Sprintf("%s:%s", host, port) } // SetSAMAddress sets the SAM address from a string in the form of "host:port" @@ -167,12 +167,9 @@ func (f *I2PConfig) Accesslisttype() string { // Accesslist returns the access list in the form of "i2cp.accessList=list" func (f *I2PConfig) Accesslist() string { if f.AccessListType != "" && len(f.AccessList) > 0 { - r := "" - for _, s := range f.AccessList { - r += s + "," - } + r := strings.Join(f.AccessList, ",") log.WithField("accessList", r).Debug("Access list generated") - return "i2cp.accessList=" + strings.TrimSuffix(r, ",") + return fmt.Sprintf(" i2cp.accessList=%s ", r) } log.Debug("Access list not set") return "" diff --git a/config/session.go b/config/session.go index 7269dc6..43773b0 100644 --- a/config/session.go +++ b/config/session.go @@ -1,6 +1,7 @@ package config import ( + "fmt" "strconv" "github.com/go-i2p/sam3/common" @@ -38,7 +39,7 @@ func (f *SessionOptions) SignatureType() string { } if f.SigType != "" { log.WithField("sigType", f.SigType).Debug("Signature type set") - return " SIGNATURE_TYPE=" + f.SigType + " " + return fmt.Sprintf(" SIGNATURE_TYPE=%s ", f.SigType) } log.Debug("Signature type not set") return "" @@ -52,7 +53,7 @@ func (f *SessionOptions) FromPort() string { } if f.InFromPort != "0" { log.WithField("fromPort", f.InFromPort).Debug("FromPort set") - return " FROM_PORT=" + f.InFromPort + " " + return fmt.Sprintf(" FROM_PORT=%s ", f.InFromPort) } log.Debug("FromPort not set") return "" @@ -66,7 +67,7 @@ func (f *SessionOptions) ToPort() string { } if f.OutToPort != "0" { log.WithField("toPort", f.OutToPort).Debug("ToPort set") - return " TO_PORT=" + f.OutToPort + " " + return fmt.Sprintf(" TO_PORT=%s ", f.OutToPort) } log.Debug("ToPort not set") return "" @@ -76,7 +77,7 @@ func (f *SessionOptions) ToPort() string { func (f *SessionOptions) SessionStyle() string { if f.Style != "" { log.WithField("style", f.Style).Debug("Session style set") - return " STYLE=" + f.Style + " " + return fmt.Sprintf(" STYLE=%s ", f.Style) } log.Debug("Using default STREAM style") return " STYLE=STREAM " diff --git a/config/transport.go b/config/transport.go index 3a2c9a5..885cb53 100644 --- a/config/transport.go +++ b/config/transport.go @@ -1,6 +1,7 @@ package config import ( + "fmt" "strconv" "time" @@ -51,7 +52,7 @@ func (f *TransportOptions) DoFastReceive() string { func (f *TransportOptions) Reliability() string { if f.MessageReliability != "" { log.WithField("reliability", f.MessageReliability).Debug("Message reliability set") - return " i2cp.messageReliability=" + f.MessageReliability + " " + return fmt.Sprintf(" i2cp.messageReliability=%s ", f.MessageReliability) } log.Debug("Message reliability not set") return "" @@ -65,7 +66,7 @@ func (f *TransportOptions) Reduce() string { "reduceIdleTime": f.ReduceIdleTimeout.String(), "reduceIdleQuantity": f.ReduceIdleQuantity, }).Debug("Reduce idle settings applied") - return "i2cp.reduceOnIdle=" + f.ReduceOnIdle() + "i2cp.reduceIdleTime=" + f.ReduceIdleTimeout.String() + "i2cp.reduceQuantity=" + f.ReduceQuantity() + return fmt.Sprintf(" i2cp.reduceOnIdle=%s i2cp.reduceIdleTime=%s i2cp.reduceQuantity=%d ", f.ReduceOnIdle(), f.ReduceIdleTimeout.String(), f.ReduceIdleQuantity) } log.Debug("Reduce idle settings not applied") return "" @@ -78,7 +79,7 @@ func (f *TransportOptions) Close() string { "closeIdle": f.CloseIdle, "closeIdleTime": f.CloseIdleTimeout.String(), }).Debug("Close idle settings applied") - return "i2cp.closeOnIdle=" + f.CloseOnIdle() + "i2cp.closeIdleTime=" + f.CloseIdleTimeout.String() + return fmt.Sprintf(" i2cp.closeOnIdle=%s i2cp.closeIdleTime=%s ", f.CloseOnIdle(), f.CloseIdleTimeout.String()) } log.Debug("Close idle settings not applied") return "" diff --git a/config/tunnel.go b/config/tunnel.go index 5c02eb0..8af3971 100644 --- a/config/tunnel.go +++ b/config/tunnel.go @@ -67,16 +67,3 @@ func (f *TunnelOptions) OutboundBackupQuantity() string { val := strconv.Itoa(f.OutBackupQuantity) return fmt.Sprintf(" outbound.backupQuantity=%s ", val) } - -// DoZero returns the zero hop settings in the form of "inbound.allowZeroHop=true outbound.allowZeroHop=true fastRecieve=true" -func (f *TunnelOptions) DoZero() string { - r := "" - if f.InAllowZeroHop { - r += " inbound.allowZeroHop=" + f.InboundDoZero() + " " - } - if f.OutAllowZeroHop { - r += " outbound.allowZeroHop= " + f.OutboundDoZero() + " " - } - log.WithField("zeroHopSettings", r).Debug("Zero hop settings applied") - return r -} diff --git a/datagram.go b/datagram.go index 96aa7ff..5324148 100644 --- a/datagram.go +++ b/datagram.go @@ -223,8 +223,7 @@ func (s *DatagramSession) WriteTo(b []byte, addr net.Addr) (n int, err error) { if s.DatagramOptions != nil { return s.writeToWithOptions(b, addr.(i2pkeys.I2PAddr)) } - - header := []byte("3.1 " + s.id + " " + addr.String() + "\n") + header := []byte(fmt.Sprintf("3.1 %s %s\n", s.id, addr.(i2pkeys.I2PAddr).String())) msg := append(header, b...) n, err = s.UDPSession.Conn.WriteToUDP(msg, s.UDPSession.RemoteAddr) if err != nil { @@ -258,7 +257,7 @@ func (s *DatagramSession) writeChunked(b []byte, addr net.Addr) (total int, err if s.DatagramOptions != nil { n, err = s.writeToWithOptions(chunk, addr.(i2pkeys.I2PAddr)) } else { - header := []byte("3.1 " + s.id + " " + addr.String() + "\n") + header := []byte(fmt.Sprintf("3.1 %s %s %d %d\n", s.id, addr.(i2pkeys.I2PAddr).String(), i, chunks)) msg := append(header, chunk...) n, err = s.UDPSession.Conn.WriteToUDP(msg, s.UDPSession.RemoteAddr) } @@ -284,24 +283,23 @@ type DatagramOptions struct { } func (s *DatagramSession) writeToWithOptions(b []byte, addr i2pkeys.I2PAddr) (n int, err error) { - var header bytes.Buffer - header.WriteString(fmt.Sprintf("3.3 %s %s", s.id, addr.String())) - + header := []byte(fmt.Sprintf("3.3 %s %s", s.id, addr.String())) if s.DatagramOptions != nil { if s.DatagramOptions.SendTags > 0 { - header.WriteString(fmt.Sprintf(" SEND_TAGS=%d", s.DatagramOptions.SendTags)) + header = append(header, []byte(fmt.Sprintf(" SEND_TAGS=%d", s.DatagramOptions.SendTags))...) } if s.DatagramOptions.TagThreshold > 0 { - header.WriteString(fmt.Sprintf(" TAG_THRESHOLD=%d", s.DatagramOptions.TagThreshold)) + header = append(header, []byte(fmt.Sprintf(" TAG_THRESHOLD=%d", s.DatagramOptions.TagThreshold))...) } if s.DatagramOptions.Expires > 0 { - header.WriteString(fmt.Sprintf(" EXPIRES=%d", s.DatagramOptions.Expires)) + header = append(header, []byte(fmt.Sprintf(" EXPIRES=%d", s.DatagramOptions.Expires))...) + } + if s.DatagramOptions.SendLeaseset { + header = append(header, []byte(" SEND_LEASESET=true")...) } - header.WriteString(fmt.Sprintf(" SEND_LEASESET=%v", s.DatagramOptions.SendLeaseset)) } - - header.WriteString("\n") - msg := append(header.Bytes(), b...) + header = append(header, '\n') + msg := append(header, b...) return s.UDPSession.Conn.WriteToUDP(msg, s.UDPSession.RemoteAddr) } diff --git a/datagram_test.go b/datagram_test.go index f14698a..3704b3c 100644 --- a/datagram_test.go +++ b/datagram_test.go @@ -4,6 +4,8 @@ import ( "fmt" "testing" "time" + + sam3opts "github.com/go-i2p/sam3/opts" ) func Test_DatagramServerClient(t *testing.T) { @@ -102,7 +104,7 @@ func ExampleDatagramSession() { myself := keys.Addr() // See the example Option_* variables. - dg, err := sam.NewDatagramSession("DGTUN", keys, Options_Small, 0) + dg, err := sam.NewDatagramSession("DGTUN", keys, sam3opts.Options_Small, 0) if err != nil { fmt.Println(err.Error()) return @@ -148,7 +150,7 @@ func ExampleMiniDatagramSession() { myself := keys.Addr() // See the example Option_* variables. - dg, err := sam.NewDatagramSession("MINIDGTUN", keys, Options_Small, 0) + dg, err := sam.NewDatagramSession("MINIDGTUN", keys, sam3opts.Options_Small, 0) if err != nil { fmt.Println(err.Error()) return diff --git a/opts/suggestedOptions.go b/opts/suggestedOptions.go new file mode 100644 index 0000000..058f098 --- /dev/null +++ b/opts/suggestedOptions.go @@ -0,0 +1,123 @@ +package sam3opts + +import ( + "net" + "os" + "strings" + + logger "github.com/go-i2p/sam3/log" + "github.com/sirupsen/logrus" +) + +var log = logger.GetSAM3Logger() + +// Examples and suggestions for options when creating sessions. +var ( + // Suitable options if you are shuffling A LOT of traffic. If unused, this + // will waste your resources. + Options_Humongous = []string{ + "inbound.length=3", "outbound.length=3", + "inbound.lengthVariance=1", "outbound.lengthVariance=1", + "inbound.backupQuantity=3", "outbound.backupQuantity=3", + "inbound.quantity=6", "outbound.quantity=6", + } + + // Suitable for shuffling a lot of traffic. + Options_Large = []string{ + "inbound.length=3", "outbound.length=3", + "inbound.lengthVariance=1", "outbound.lengthVariance=1", + "inbound.backupQuantity=1", "outbound.backupQuantity=1", + "inbound.quantity=4", "outbound.quantity=4", + } + + // Suitable for shuffling a lot of traffic quickly with minimum + // anonymity. Uses 1 hop and multiple tunnels. + Options_Wide = []string{ + "inbound.length=1", "outbound.length=1", + "inbound.lengthVariance=1", "outbound.lengthVariance=1", + "inbound.backupQuantity=2", "outbound.backupQuantity=2", + "inbound.quantity=3", "outbound.quantity=3", + } + + // Suitable for shuffling medium amounts of traffic. + Options_Medium = []string{ + "inbound.length=3", "outbound.length=3", + "inbound.lengthVariance=1", "outbound.lengthVariance=1", + "inbound.backupQuantity=0", "outbound.backupQuantity=0", + "inbound.quantity=2", "outbound.quantity=2", + } + + // Sensible defaults for most people + Options_Default = []string{ + "inbound.length=3", "outbound.length=3", + "inbound.lengthVariance=0", "outbound.lengthVariance=0", + "inbound.backupQuantity=1", "outbound.backupQuantity=1", + "inbound.quantity=1", "outbound.quantity=1", + } + + // Suitable only for small dataflows, and very short lasting connections: + // You only have one tunnel in each direction, so if any of the nodes + // through which any of your two tunnels pass through go offline, there will + // be a complete halt in the dataflow, until a new tunnel is built. + Options_Small = []string{ + "inbound.length=3", "outbound.length=3", + "inbound.lengthVariance=1", "outbound.lengthVariance=1", + "inbound.backupQuantity=0", "outbound.backupQuantity=0", + "inbound.quantity=1", "outbound.quantity=1", + } + + // Does not use any anonymization, you connect directly to others tunnel + // endpoints, thus revealing your identity but not theirs. Use this only + // if you don't care. + Options_Warning_ZeroHop = []string{ + "inbound.length=0", "outbound.length=0", + "inbound.lengthVariance=0", "outbound.lengthVariance=0", + "inbound.backupQuantity=0", "outbound.backupQuantity=0", + "inbound.quantity=2", "outbound.quantity=2", + } +) + +func getEnv(key, fallback string) string { + logger.InitializeSAM3Logger() + value, ok := os.LookupEnv(key) + if !ok { + log.WithFields(logrus.Fields{ + "key": key, + "fallback": fallback, + }).Debug("Environment variable not set, using fallback") + return fallback + } + log.WithFields(logrus.Fields{ + "key": key, + "value": value, + }).Debug("Retrieved environment variable") + return value +} + +var ( + SAM_HOST = getEnv("sam_host", "127.0.0.1") + SAM_PORT = getEnv("sam_port", "7656") +) + +func SAMDefaultAddr(fallforward string) string { + if fallforward == "" { + addr := net.JoinHostPort(SAM_HOST, SAM_PORT) + log.WithField("addr", addr).Debug("Using default SAM address") + return addr + } + log.WithField("addr", fallforward).Debug("Using fallforward SAM address") + return fallforward +} + +func GenerateOptionString(opts []string) string { + optStr := strings.Join(opts, " ") + log.WithField("options", optStr).Debug("Generating option string") + if strings.Contains(optStr, "i2cp.leaseSetEncType") { + log.Debug("i2cp.leaseSetEncType already present in options") + return optStr + } + finalOpts := optStr + " i2cp.leaseSetEncType=4,0" + log.WithField("finalOptions", finalOpts).Debug("Added default i2cp.leaseSetEncType to options") + return finalOpts + // return optStr + " i2cp.leaseSetEncType=4,0" +} diff --git a/primary.go b/primary.go index 4d17a52..20fce99 100644 --- a/primary.go +++ b/primary.go @@ -295,15 +295,7 @@ func (sam *PrimarySession) newGenericSubSessionWithSignatureAndPorts(style, id, log.WithFields(logrus.Fields{"style": style, "id": id, "from": from, "to": to, "extras": extras}).Debug("newGenericSubSessionWithSignatureAndPorts called") conn := sam.conn - fp := "" - tp := "" - if from != "0" && from != "" { - fp = " FROM_PORT=" + from - } - if to != "0" && to != "" { - tp = " TO_PORT=" + to - } - scmsg := []byte("SESSION ADD STYLE=" + style + " ID=" + id + fp + tp + " " + strings.Join(extras, " ") + "\n") + scmsg := []byte(fmt.Sprintf("SESSION ADD STYLE=%s ID=%s FROM_PORT=%s TO_PORT=%s %s\n", style, id, from, to, strings.Join(extras, " "))) log.WithField("message", string(scmsg)).Debug("Sending SESSION ADD message") diff --git a/stream.go b/stream.go index 8925d82..8ff5827 100644 --- a/stream.go +++ b/stream.go @@ -297,7 +297,7 @@ func (s *StreamSession) DialI2P(addr i2pkeys.I2PAddr) (*SAMConn, error) { default: log.WithField("error", scanner.Text()).Error("Unknown error") conn.Close() - return nil, errors.New("Unknown error: " + scanner.Text() + " : " + string(buf[:n])) + return nil, fmt.Errorf("Unknown error: %s : %s", scanner.Text(), string(buf[:n])) } } log.Panic("Unexpected end of StreamSession.DialI2P()") diff --git a/stream_test.go b/stream_test.go index 8add136..7374c78 100644 --- a/stream_test.go +++ b/stream_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/go-i2p/i2pkeys" + sam3opts "github.com/go-i2p/sam3/opts" ) func Test_StreamingDial(t *testing.T) { @@ -164,7 +165,7 @@ func ExampleStreamSession() { return } // See the example Option_* variables. - ss, err := sam.NewStreamSession("stream_example", keys, Options_Small) + ss, err := sam.NewStreamSession("stream_example", keys, sam3opts.Options_Small) if err != nil { fmt.Println(err.Error()) return @@ -236,7 +237,7 @@ func ExampleStreamListener() { fmt.Println(err.Error()) return } - cs, err := csam.NewStreamSession("client_example", keys, Options_Small) + cs, err := csam.NewStreamSession("client_example", keys, sam3opts.Options_Small) if err != nil { fmt.Println(err.Error()) quit <- false @@ -259,7 +260,7 @@ func ExampleStreamListener() { quit <- true }(keys.Addr()) // end of client - ss, err := sam.NewStreamSession("server_example", keys, Options_Small) + ss, err := sam.NewStreamSession("server_example", keys, sam3opts.Options_Small) if err != nil { fmt.Println(err.Error()) return diff --git a/suggestedOptions.go b/suggestedOptions.go index af48db5..92f087f 100644 --- a/suggestedOptions.go +++ b/suggestedOptions.go @@ -7,75 +7,10 @@ import ( "strings" logger "github.com/go-i2p/sam3/log" + sam3opts "github.com/go-i2p/sam3/opts" "github.com/sirupsen/logrus" ) -// Examples and suggestions for options when creating sessions. -var ( - // Suitable options if you are shuffling A LOT of traffic. If unused, this - // will waste your resources. - Options_Humongous = []string{ - "inbound.length=3", "outbound.length=3", - "inbound.lengthVariance=1", "outbound.lengthVariance=1", - "inbound.backupQuantity=3", "outbound.backupQuantity=3", - "inbound.quantity=6", "outbound.quantity=6", - } - - // Suitable for shuffling a lot of traffic. - Options_Large = []string{ - "inbound.length=3", "outbound.length=3", - "inbound.lengthVariance=1", "outbound.lengthVariance=1", - "inbound.backupQuantity=1", "outbound.backupQuantity=1", - "inbound.quantity=4", "outbound.quantity=4", - } - - // Suitable for shuffling a lot of traffic quickly with minimum - // anonymity. Uses 1 hop and multiple tunnels. - Options_Wide = []string{ - "inbound.length=1", "outbound.length=1", - "inbound.lengthVariance=1", "outbound.lengthVariance=1", - "inbound.backupQuantity=2", "outbound.backupQuantity=2", - "inbound.quantity=3", "outbound.quantity=3", - } - - // Suitable for shuffling medium amounts of traffic. - Options_Medium = []string{ - "inbound.length=3", "outbound.length=3", - "inbound.lengthVariance=1", "outbound.lengthVariance=1", - "inbound.backupQuantity=0", "outbound.backupQuantity=0", - "inbound.quantity=2", "outbound.quantity=2", - } - - // Sensible defaults for most people - Options_Default = []string{ - "inbound.length=3", "outbound.length=3", - "inbound.lengthVariance=0", "outbound.lengthVariance=0", - "inbound.backupQuantity=1", "outbound.backupQuantity=1", - "inbound.quantity=1", "outbound.quantity=1", - } - - // Suitable only for small dataflows, and very short lasting connections: - // You only have one tunnel in each direction, so if any of the nodes - // through which any of your two tunnels pass through go offline, there will - // be a complete halt in the dataflow, until a new tunnel is built. - Options_Small = []string{ - "inbound.length=3", "outbound.length=3", - "inbound.lengthVariance=1", "outbound.lengthVariance=1", - "inbound.backupQuantity=0", "outbound.backupQuantity=0", - "inbound.quantity=1", "outbound.quantity=1", - } - - // Does not use any anonymization, you connect directly to others tunnel - // endpoints, thus revealing your identity but not theirs. Use this only - // if you don't care. - Options_Warning_ZeroHop = []string{ - "inbound.length=0", "outbound.length=0", - "inbound.lengthVariance=0", "outbound.lengthVariance=0", - "inbound.backupQuantity=0", "outbound.backupQuantity=0", - "inbound.quantity=2", "outbound.quantity=2", - } -) - func PrimarySessionString() string { log.Debug("Determining primary session type") _, err := http.Get("http://127.0.0.1:7070") @@ -99,7 +34,7 @@ func PrimarySessionString() string { log.WithError(err).Debug("Failed to create new keys, assuming MASTER session") return "MASTER" } - primarySession, err := testSam.newPrimarySession("PRIMARY", "primaryTestTunnel", newKeys, Options_Small) + primarySession, err := testSam.newPrimarySession("PRIMARY", "primaryTestTunnel", newKeys, sam3opts.Options_Small) if err != nil { log.WithError(err).Debug("Failed to create primary session, assuming MASTER session") return "MASTER"