Loading internal/kraken.go +42 −7 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ import ( "net" "os" "reflect" "regexp" "strconv" "strings" "time" Loading @@ -33,6 +34,11 @@ const ( RecordEndPrefix = "-----END SIGNATURE-----" ) var ( uncommentedComma = regexp.MustCompile("[^\\\\],") uncommentedEqual = regexp.MustCompile("[^\\\\]=") ) type flicker struct { speed int flickered bool Loading Loading @@ -441,7 +447,8 @@ func parseExtrainfoDoc(r io.Reader) (map[string]*resources.Bridge, error) { t.Fingerprint = b.Fingerprint err := populateTransportInfo(line, t) if err != nil { return nil, err log.Println(err) continue } b.AddTransport(t) } Loading Loading @@ -503,13 +510,41 @@ func populateTransportInfo(transport string, t *resources.Transport) error { // We may be dealing with one or more key=value pairs. if len(words) > MinTransportWords { args := strings.Split(words[3], ",") for _, arg := range args { kv := strings.Split(arg, "=") if len(kv) != 2 { return fmt.Errorf("key:value pair in %q not separated by a '='", words[3]) args := words[3] parseArg := func(start, end int) error { arg := args[start:end] arg = strings.ReplaceAll(arg, "\\,", ",") argIndexes := uncommentedEqual.FindAllStringIndex(arg, -1) if len(argIndexes) != 1 { return fmt.Errorf("transport arg has an unsupported format: %s", arg) } key := arg[0 : argIndexes[0][1]-1] key = strings.ReplaceAll(key, "\\=", "=") value := arg[argIndexes[0][1]:] value = strings.ReplaceAll(value, "\\=", "=") t.Parameters[key] = value return nil } t.Parameters[kv[0]] = kv[1] start := 0 for _, index := range uncommentedComma.FindAllStringIndex(args, -1) { if len(index) != 2 { return fmt.Errorf("transport args has an unsupported format: %s", args) } err := parseArg(start, index[1]-1) if err != nil { return err } start = index[1] } err := parseArg(start, len(args)) if err != nil { return err } } Loading internal/kraken_test.go +80 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ package internal import ( "reflect" "slices" "testing" Loading Loading @@ -269,3 +270,82 @@ func TestBridgeWithPTnotAsVanilla(t *testing.T) { } } } func TestTransportInfo(t *testing.T) { type transportInfo struct { Type string IPVer core.IPVersion Address string Port uint16 Parameters map[string]string } transportLines := map[string]transportInfo{ "transport obfs4 139.55.50.64:39071 cert=ZZZZZZZZZZZ,iat-mode=0": transportInfo{ Type: "obfs4", IPVer: core.IPv4, Address: "139.55.50.64", Port: 39071, Parameters: map[string]string{"cert": "ZZZZZZZZZZZ", "iat-mode": "0"}, }, "transport obfs4 [2a0c:4d80:42:702::1]:27015 cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw,iat-mode=0": transportInfo{ Type: "obfs4", IPVer: core.IPv6, Address: "2a0c:4d80:42:702::1", Port: 27015, Parameters: map[string]string{"cert": "TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw", "iat-mode": "0"}, }, "transport webtunnel [2001:db8:d21c::2bc4]:443 url=https://example.com/something-random": transportInfo{ Type: "webtunnel", IPVer: core.IPAny, Address: "2001:db8:d21c::2bc4", Port: 443, Parameters: map[string]string{"url": "https://example.com/something-random"}, }, "transport obfs4 139.55.50.64:39071 cert=Z\\=Z\\=Z,iat-mode=0": transportInfo{ Type: "obfs4", IPVer: core.IPv4, Address: "139.55.50.64", Port: 39071, Parameters: map[string]string{"cert": "Z=Z=Z", "iat-mode": "0"}, }, "transport obfs4 139.55.50.64:39071 cert=Z\\,Z\\,Z,iat-mode=0": transportInfo{ Type: "obfs4", IPVer: core.IPv4, Address: "139.55.50.64", Port: 39071, Parameters: map[string]string{"cert": "Z,Z,Z", "iat-mode": "0"}, }, "transport obfs4 139.55.50.64:39071 cert=Z\\,\\=Z\\=Z\\,,ia\\,t-m\\=ode\\==0": transportInfo{ Type: "obfs4", IPVer: core.IPv4, Address: "139.55.50.64", Port: 39071, Parameters: map[string]string{"cert": "Z,=Z=Z,", "ia,t-m=ode=": "0"}, }, } for line, transport := range transportLines { parsedTransport := resources.NewTransport() err := populateTransportInfo(line, parsedTransport) if err != nil { t.Error("Error propulating transport info for ", line, err) continue } if !reflect.DeepEqual(parsedTransport.Parameters, transport.Parameters) { t.Error(line, "didn't produce the right parameters:", parsedTransport.Parameters) } if parsedTransport.Type() != transport.Type { t.Error(line, "didn't produce the right type:", parsedTransport.Type()) } if parsedTransport.IPVer != transport.IPVer { t.Error(line, "didn't produce the right IPVer:", parsedTransport.IPVer) } if parsedTransport.Address.String() != transport.Address { t.Error(line, "didn't produce the right address:", parsedTransport.Address.String()) } if parsedTransport.Port != transport.Port { t.Error(line, "didn't produce the right port:", parsedTransport.Port) } } } Loading
internal/kraken.go +42 −7 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ import ( "net" "os" "reflect" "regexp" "strconv" "strings" "time" Loading @@ -33,6 +34,11 @@ const ( RecordEndPrefix = "-----END SIGNATURE-----" ) var ( uncommentedComma = regexp.MustCompile("[^\\\\],") uncommentedEqual = regexp.MustCompile("[^\\\\]=") ) type flicker struct { speed int flickered bool Loading Loading @@ -441,7 +447,8 @@ func parseExtrainfoDoc(r io.Reader) (map[string]*resources.Bridge, error) { t.Fingerprint = b.Fingerprint err := populateTransportInfo(line, t) if err != nil { return nil, err log.Println(err) continue } b.AddTransport(t) } Loading Loading @@ -503,13 +510,41 @@ func populateTransportInfo(transport string, t *resources.Transport) error { // We may be dealing with one or more key=value pairs. if len(words) > MinTransportWords { args := strings.Split(words[3], ",") for _, arg := range args { kv := strings.Split(arg, "=") if len(kv) != 2 { return fmt.Errorf("key:value pair in %q not separated by a '='", words[3]) args := words[3] parseArg := func(start, end int) error { arg := args[start:end] arg = strings.ReplaceAll(arg, "\\,", ",") argIndexes := uncommentedEqual.FindAllStringIndex(arg, -1) if len(argIndexes) != 1 { return fmt.Errorf("transport arg has an unsupported format: %s", arg) } key := arg[0 : argIndexes[0][1]-1] key = strings.ReplaceAll(key, "\\=", "=") value := arg[argIndexes[0][1]:] value = strings.ReplaceAll(value, "\\=", "=") t.Parameters[key] = value return nil } t.Parameters[kv[0]] = kv[1] start := 0 for _, index := range uncommentedComma.FindAllStringIndex(args, -1) { if len(index) != 2 { return fmt.Errorf("transport args has an unsupported format: %s", args) } err := parseArg(start, index[1]-1) if err != nil { return err } start = index[1] } err := parseArg(start, len(args)) if err != nil { return err } } Loading
internal/kraken_test.go +80 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ package internal import ( "reflect" "slices" "testing" Loading Loading @@ -269,3 +270,82 @@ func TestBridgeWithPTnotAsVanilla(t *testing.T) { } } } func TestTransportInfo(t *testing.T) { type transportInfo struct { Type string IPVer core.IPVersion Address string Port uint16 Parameters map[string]string } transportLines := map[string]transportInfo{ "transport obfs4 139.55.50.64:39071 cert=ZZZZZZZZZZZ,iat-mode=0": transportInfo{ Type: "obfs4", IPVer: core.IPv4, Address: "139.55.50.64", Port: 39071, Parameters: map[string]string{"cert": "ZZZZZZZZZZZ", "iat-mode": "0"}, }, "transport obfs4 [2a0c:4d80:42:702::1]:27015 cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw,iat-mode=0": transportInfo{ Type: "obfs4", IPVer: core.IPv6, Address: "2a0c:4d80:42:702::1", Port: 27015, Parameters: map[string]string{"cert": "TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw", "iat-mode": "0"}, }, "transport webtunnel [2001:db8:d21c::2bc4]:443 url=https://example.com/something-random": transportInfo{ Type: "webtunnel", IPVer: core.IPAny, Address: "2001:db8:d21c::2bc4", Port: 443, Parameters: map[string]string{"url": "https://example.com/something-random"}, }, "transport obfs4 139.55.50.64:39071 cert=Z\\=Z\\=Z,iat-mode=0": transportInfo{ Type: "obfs4", IPVer: core.IPv4, Address: "139.55.50.64", Port: 39071, Parameters: map[string]string{"cert": "Z=Z=Z", "iat-mode": "0"}, }, "transport obfs4 139.55.50.64:39071 cert=Z\\,Z\\,Z,iat-mode=0": transportInfo{ Type: "obfs4", IPVer: core.IPv4, Address: "139.55.50.64", Port: 39071, Parameters: map[string]string{"cert": "Z,Z,Z", "iat-mode": "0"}, }, "transport obfs4 139.55.50.64:39071 cert=Z\\,\\=Z\\=Z\\,,ia\\,t-m\\=ode\\==0": transportInfo{ Type: "obfs4", IPVer: core.IPv4, Address: "139.55.50.64", Port: 39071, Parameters: map[string]string{"cert": "Z,=Z=Z,", "ia,t-m=ode=": "0"}, }, } for line, transport := range transportLines { parsedTransport := resources.NewTransport() err := populateTransportInfo(line, parsedTransport) if err != nil { t.Error("Error propulating transport info for ", line, err) continue } if !reflect.DeepEqual(parsedTransport.Parameters, transport.Parameters) { t.Error(line, "didn't produce the right parameters:", parsedTransport.Parameters) } if parsedTransport.Type() != transport.Type { t.Error(line, "didn't produce the right type:", parsedTransport.Type()) } if parsedTransport.IPVer != transport.IPVer { t.Error(line, "didn't produce the right IPVer:", parsedTransport.IPVer) } if parsedTransport.Address.String() != transport.Address { t.Error(line, "didn't produce the right address:", parsedTransport.Address.String()) } if parsedTransport.Port != transport.Port { t.Error(line, "didn't produce the right port:", parsedTransport.Port) } } }