package config import ( "context" "encoding/base64" "fmt" "mpbl3p/crypto" "mpbl3p/crypto/sharedkey" "mpbl3p/proxy" "mpbl3p/tcp" "mpbl3p/udp" "mpbl3p/udp/congestion" "time" ) func (c Configuration) Build(ctx context.Context, source proxy.Source, sink proxy.Sink) (*proxy.Proxy, error) { p := proxy.NewProxy(0) var g func() proxy.MacGenerator var v func() proxy.MacVerifier switch c.Host.Crypto { case "None": g = func() proxy.MacGenerator { return crypto.None{} } v = func() proxy.MacVerifier { return crypto.None{} } case "Blake2s": key, err := base64.StdEncoding.DecodeString(c.Host.SharedKey) if err != nil { return nil, err } if _, err := sharedkey.NewBlake2s(key); err != nil { return nil, err } g = func() proxy.MacGenerator { g, _ := sharedkey.NewBlake2s(key) return g } v = func() proxy.MacVerifier { v, _ := sharedkey.NewBlake2s(key) return v } } p.Source = source p.Sink = sink for _, peer := range c.Peers { switch peer.Method { case "TCP": if err := buildTcp(ctx, p, peer, g, v); err != nil { return nil, err } case "UDP": if err := buildUdp(ctx, p, peer, g, v); err != nil { return nil, err } } } return p, nil } func buildTcp(ctx context.Context, p *proxy.Proxy, peer Peer, g func() proxy.MacGenerator, v func() proxy.MacVerifier) error { var laddr func() string if peer.LocalPort == 0 { laddr = func() string { return fmt.Sprintf("%s:", peer.GetLocalHost()) } } else { laddr = func() string { return fmt.Sprintf("%s:%d", peer.GetLocalHost(), peer.LocalPort) } } if peer.RemoteHost != "" { f, err := tcp.InitiateFlow(laddr, fmt.Sprintf("%s:%d", peer.RemoteHost, peer.RemotePort)) if err != nil { return err } p.AddConsumer(ctx, f, g()) p.AddProducer(ctx, f, v()) return nil } err := tcp.NewListener(ctx, p, laddr(), v, g) if err != nil { return err } return nil } func buildUdp(ctx context.Context, p *proxy.Proxy, peer Peer, g func() proxy.MacGenerator, v func() proxy.MacVerifier) error { var laddr func() string if peer.LocalPort == 0 { laddr = func() string { return fmt.Sprintf("%s:", peer.GetLocalHost()) } } else { laddr = func() string { return fmt.Sprintf("%s:%d", peer.GetLocalHost(), peer.LocalPort) } } var c func() udp.Congestion switch peer.Congestion { case "None": c = func() udp.Congestion { return congestion.NewNone() } default: fallthrough case "NewReno": c = func() udp.Congestion { return congestion.NewNewReno() } } if peer.RemoteHost != "" { f, err := udp.InitiateFlow( laddr, fmt.Sprintf("%s:%d", peer.RemoteHost, peer.RemotePort), v(), g(), c(), time.Duration(peer.KeepAlive)*time.Second, ) if err != nil { return err } p.AddConsumer(ctx, f, g()) p.AddProducer(ctx, f, v()) return nil } err := udp.NewListener(ctx, p, laddr(), v, g, c) if err != nil { return err } return nil }