From 5c369f00d46d94207e853e9af6f5eee2b96b3987 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 23 Jan 2014 11:28:30 -0800 Subject: [PATCH] Adding base socks server --- socks5.go | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 socks5.go diff --git a/socks5.go b/socks5.go new file mode 100644 index 0000000..a6a6932 --- /dev/null +++ b/socks5.go @@ -0,0 +1,108 @@ +package socks5 + +import ( + "bufio" + "fmt" + "log" + "net" +) + +const ( + socks5Version = uint8(5) +) + +// Config is used to setup and configure a Server +type Config struct { + // If provided, username/password authentication is enabled + // otherwise, non-authenticated mode is allowed + Credentials CredentialStore + + // Resolver can be provided to do custom name resolution. + // Defaults to DNSResolver if not provided. + Resolver NameResolver + + // Rules is provided to enable custom logic around permitting + // various commands. If not provided, PermitAll is used. + Rules RuleSet +} + +// Server is reponsible for accepting connections and handling +// the details of the SOCKS5 protocol +type Server struct { + config *Config +} + +// New creates a new Server and potentially returns an error +func New(conf *Config) (*Server, error) { + // Ensure we have a DNS resolver + if conf.Resolver == nil { + conf.Resolver = DNSResolver{} + } + + // Ensure we have a rule set + if conf.Rules == nil { + conf.Rules = PermitAll() + } + + server := &Server{ + config: conf, + } + return server, nil +} + +// ListenAndServe is used to create a listener and serve on it +func (s *Server) ListenAndServe(network, addr string) error { + l, err := net.Listen(network, addr) + if err != nil { + return err + } + return s.Serve(l) +} + +// Serve is used to serve connections from a listener +func (s *Server) Serve(l net.Listener) error { + for { + conn, err := l.Accept() + if err != nil { + return err + } + go s.ServeConn(conn) + } + return nil +} + +// ServeConn is used to serve a single connection. +func (s *Server) ServeConn(conn net.Conn) error { + defer conn.Close() + bufConn := bufio.NewReader(conn) + + // Read the version byte + version := []byte{0} + if _, err := bufConn.Read(version); err != nil { + log.Printf("[ERR] Failed to get version byte: %v", err) + return err + } + + // Ensure we are compatible + if version[0] != socks5Version { + err := fmt.Errorf("Unsupported SOCKS version: %v", version) + log.Printf("[ERR] %v", err) + return err + } + + // Authenticate the connection + if err := s.authenticate(conn, bufConn); err != nil { + err = fmt.Errorf("Failed to authenticate: %v", err) + log.Printf("[ERR] %v", err) + return err + } + + // Process the client request + if err := s.handleRequest(conn, bufConn); err != nil { + err = fmt.Errorf("Failed to handle request: %v", err) + log.Printf("[ERR] %v", err) + return err + } + + return nil +}