Backport: parsing improvement + tests

This commit is contained in:
kayos@tcp.direct 2022-08-28 22:41:34 -07:00
parent 0b8aecb1c8
commit aebdfe2131
Signed by: kayos
GPG Key ID: 4B841471B4BEE979
4 changed files with 204 additions and 69 deletions

13
internal/pools/strings.go Normal file
View File

@ -0,0 +1,13 @@
package pools
import (
"strings"
"sync"
)
var CopABuffer = &sync.Pool{New: func() interface{} { return &strings.Builder{} }}
func DiscardBuffer(buf *strings.Builder) {
buf.Reset()
CopABuffer.Put(buf)
}

View File

@ -2,16 +2,12 @@ package prox5
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
"sync/atomic"
"time"
"github.com/miekg/dns"
ipa "inet.af/netaddr"
)
// throw shit proxies here, get map
@ -22,70 +18,6 @@ func init() {
inChan = make(chan string, 100000)
}
func checkV6(in string) (filtered string, ok bool) {
split := strings.Split(in, "]:")
if len(split) != 2 {
return in, false
}
combo, err := ipa.ParseIPPort(split[0] + "]:" + split[1])
if err != nil {
return in, false
}
if !strings.Contains(split[1], ":") {
return combo.String(), true
}
split6 := strings.Split(split[1], ":")
if len(split6) != 2 {
return in, false
}
return fmt.Sprintf("%s:%s@%s", split6[0], split6[1], combo.String()), true
}
func (s *Swamp) filter(in string) (filtered string, ok bool) {
if !strings.Contains(in, ":") {
return in, false
}
split := strings.Split(in, ":")
if len(split) < 2 {
return in, false
}
if _, err := strconv.Atoi(split[1]); err != nil {
return in, false
}
switch len(split) {
case 2:
if _, ok := dns.IsDomainName(split[0]); ok {
return in, true
}
combo, err := ipa.ParseIPPort(in)
if err != nil {
return in, false
}
return combo.String(), true
case 4:
if _, ok := dns.IsDomainName(split[0]); ok {
return fmt.Sprintf("%s:%s@%s:%s", split[2], split[3], split[0], split[1]), true
}
combo, err := ipa.ParseIPPort(split[0] + ":" + split[1])
if err != nil {
return in, false
}
return fmt.Sprintf("%s:%s@%s", split[2], split[3], combo.String()), true
default:
if !strings.Contains(split[0], "[") || !strings.Contains(split[0], "]:") {
return in, false
}
}
return checkV6(in)
}
// LoadProxyTXT loads proxies from a given seed file and feeds them to the mapBuilder to be later queued automatically for validation.
// Expects the following formats:
// * 127.0.0.1:1080
@ -125,7 +57,7 @@ func (s *Swamp) LoadProxyTXT(seedFile string) int {
// LoadSingleProxy loads a SOCKS proxy into our map. Uses the format: 127.0.0.1:1080 (host:port).
func (s *Swamp) LoadSingleProxy(sock string) (ok bool) {
if sock, ok = s.filter(sock); !ok {
if sock, ok = filter(sock); !ok {
return
}
go s.loadSingleProxy(sock)

106
parse.go Normal file
View File

@ -0,0 +1,106 @@
package prox5
import (
"strconv"
"strings"
"github.com/miekg/dns"
ipa "inet.af/netaddr"
"git.tcp.direct/kayos/prox5/internal/pools"
)
func filterv6(in string) (filtered string, ok bool) {
split := strings.Split(in, "]:")
if len(split) < 2 {
return "", false
}
split2 := strings.Split(split[1], ":")
switch len(split2) {
case 0:
combo, err := ipa.ParseIPPort(buildProxyString("", "", split[0], split2[0], true))
if err == nil {
return combo.String(), true
}
case 1:
concat := buildProxyString("", "", split[0], split2[0], true)
combo, err := ipa.ParseIPPort(concat)
if err == nil {
return combo.String(), true
}
default:
_, err := ipa.ParseIPPort(buildProxyString("", "", split[0], split2[0], true))
if err == nil {
return buildProxyString(split2[1], split2[2], split[0], split2[0], true), true
}
}
return "", true
}
func isNumber(s string) bool {
_, err := strconv.Atoi(s)
return err == nil
}
func buildProxyString(username, password, address, port string, v6 bool) (result string) {
builder := pools.CopABuffer.Get().(*strings.Builder)
if username != "" && password != "" {
builder.WriteString(username)
builder.WriteString(":")
builder.WriteString(password)
builder.WriteString("@")
}
builder.WriteString(address)
if v6 {
builder.WriteString("]")
}
builder.WriteString(":")
builder.WriteString(port)
result = builder.String()
pools.DiscardBuffer(builder)
return
}
func filter(in string) (filtered string, ok bool) { //nolint:cyclop
if !strings.Contains(in, ":") {
return "", false
}
split := strings.Split(in, ":")
if len(split) < 2 {
return "", false
}
switch len(split) {
case 2:
_, isDomain := dns.IsDomainName(split[0])
if isDomain && isNumber(split[1]) {
return in, true
}
combo, err := ipa.ParseIPPort(in)
if err != nil {
return "", false
}
return combo.String(), true
case 4:
_, isDomain := dns.IsDomainName(split[0])
if isDomain && isNumber(split[1]) {
return buildProxyString(split[2], split[3], split[0], split[1], false), true
}
_, isDomain = dns.IsDomainName(split[2])
if isDomain && isNumber(split[3]) {
return buildProxyString(split[0], split[1], split[2], split[3], false), true
}
if _, err := ipa.ParseIPPort(split[2] + ":" + split[3]); err == nil {
return buildProxyString(split[0], split[1], split[2], split[3], false), true
}
if _, err := ipa.ParseIPPort(split[0] + ":" + split[1]); err == nil {
return buildProxyString(split[2], split[3], split[0], split[1], false), true
}
default:
if !strings.Contains(in, "[") || !strings.Contains(in, "]:") {
return "", false
}
}
return filterv6(in)
}

84
parse_test.go Normal file
View File

@ -0,0 +1,84 @@
package prox5
import "testing"
func Test_filter(t *testing.T) {
type args struct {
in string
}
type test struct {
name string
args args
wantFiltered string
wantOk bool
}
var tests = []test{
{
name: "simple",
args: args{
in: "127.0.0.1:1080",
},
wantFiltered: "127.0.0.1:1080",
wantOk: true,
},
{
name: "withAuth",
args: args{
in: "127.0.0.1:1080:user:pass",
},
wantFiltered: "user:pass@127.0.0.1:1080",
wantOk: true,
},
{
name: "simpleDomain",
args: args{
in: "yeet.com:1080",
},
wantFiltered: "yeet.com:1080",
wantOk: true,
},
{
name: "domainWithAuth",
args: args{
in: "yeet.com:1080:user:pass",
},
wantFiltered: "user:pass@yeet.com:1080",
wantOk: true,
},
{
name: "ipv6",
args: args{
in: "[fe80::2ef0:5dff:fe7f:c299]:1080",
},
wantFiltered: "[fe80::2ef0:5dff:fe7f:c299]:1080",
wantOk: true,
},
{
name: "ipv6WithAuth",
args: args{
in: "[fe80::2ef0:5dff:fe7f:c299]:1080:user:pass",
},
wantFiltered: "user:pass@[fe80::2ef0:5dff:fe7f:c299]:1080",
wantOk: true,
},
{
name: "invalid",
args: args{
in: "yeet",
},
wantFiltered: "",
wantOk: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotFiltered, gotOk := filter(tt.args.in)
if gotFiltered != tt.wantFiltered {
t.Errorf("filter() gotFiltered = %v, want %v", gotFiltered, tt.wantFiltered)
}
if gotOk != tt.wantOk {
t.Errorf("filter() gotOk = %v, want %v", gotOk, tt.wantOk)
}
})
}
}