// Serve parse data and then send to mika server. func (h *Relay) Serve() { bf := bufio.NewReader(h.conn) req, err := http.ReadRequest(bf) if err != nil { utils.Errorf("Read request error %s", err) return } // TODO Set http protocol flag mikaConn, err := mika.DailWithRawAddrHTTP("tcp", h.ssServer, utils.ToAddr(req.URL.Host), h.cipher) if err != nil { return } defer func() { if !h.closed { err := mikaConn.Close() utils.Errorf("Close connection error %v\n", err) } }() if req.Method == "CONNECT" { _HTTPSHandler(h.conn) } else { _HTTPHandler(mikaConn, req) } go protocols.Pipe(h.conn, mikaConn) protocols.Pipe(mikaConn, h.conn) h.closed = true }
func tcpServe(localConf *utils.LocalConf) { nl, err := net.Listen("tcp", fmt.Sprintf("%s:%d", localConf.Address, localConf.Port)) if err != nil { utils.Fatalf("Create server error %s", err) } defer nl.Close() utils.Infof("Client listen on %s://%s:%d", localConf.Protocol, localConf.Address, localConf.Port) var handleFunc func(c protocols.Protocol) switch localConf.Protocol { case "http": handleFunc = handleHTTP case "socks5": handleFunc = handleSocks5 } for { c, err := nl.Accept() if err != nil { utils.Errorf("Local connection accept error %s", err) continue } utils.Infof("Get local connection from %s", c.RemoteAddr()) go handleFunc(c) } }
// Serve handles connection between socks5 client and remote addr. func (s *TCPRelay) Serve() (err error) { defer func() { if !s.closed { s.conn.Close() } }() s.handShake() cmd, rawAddr, addr, err := s.parseRequest() if err != nil { utils.Errorf("Parse request error %v\n", err) return } utils.Infof("Proxy connection to %s\n", string(addr)) s.reply() switch cmd { case CONNECT: s.connect(rawAddr) case UDP_ASSOCIATE: s.udpAssociate() case BIND: default: err = fmt.Errorf("unknow cmd type") } return }
func (c *Mika) Read(b []byte) (n int, err error) { // recover() avoid panic var buf = c.readBuf // dataLen := len(b) if c.serverSide { // ------------------------------ // | dataLen | hmac | user data | // ------------------------------ // | 2 | 10 | Variable | // ------------------------------ const datePos = 12 if _, err := io.ReadFull(c.Conn, buf[:datePos]); err != nil { return 0, err } dataLen := int(binary.BigEndian.Uint16(buf[:2])) expectedhmac := make([]byte, 10) copy(expectedhmac, buf[2:datePos]) utils.Debugf("dataLen %d expected len %d", dataLen, len(b)) if dataLen > len(b) { utils.Errorf("Date len %d large than b %d", dataLen, len(b)) return 0, fmt.Errorf("Too large data") } if _, err := io.ReadFull(c.Conn, b[:dataLen]); err != nil { utils.Errorf("Read error %s", err) return 0, err } c.header.ChunkID++ utils.Debugf("ChunkID %d, receive %d datas, expectedhmac %#v ", c.header.ChunkID, dataLen, expectedhmac) _, hmac := otaReqChunkAuth(c.iv, c.header.ChunkID, b[:dataLen]) if !bytes.Equal(hmac, expectedhmac) { utils.Errorf("Hmac %#v mismatch with %#v, remote addr %s", hmac, expectedhmac, c.RemoteAddr()) return 0, fmt.Errorf("Hmac mismatch") } // if dataLen > b // we should buffer remains. return dataLen, nil } return c.Conn.Read(b) }
func handle(c protocols.Protocol, cg *mika.CryptoGenerator) { mikaConn, err := mika.NewMika(c, cg.NewCrypto(), nil) if err != nil { c.Close() utils.Errorf("Create mika connection error %s", err) return } mika.Serve(mikaConn) }
// connect handles CONNECT cmd // Here is a bit magic. It acts as a mika client that redirects conntion to mika server. func (s *TCPRelay) connect(rawAddr []byte) (err error) { // TODO Dail("tcp", rawAdd) would be more reasonable. mikaConn, err := mika.DailWithRawAddr("tcp", s.ssServer, rawAddr, s.cipher) if err != nil { return } defer func() { if !s.closed { err := mikaConn.Close() utils.Errorf("Close connection error %v\n", err) } }() go protocols.Pipe(s.conn, mikaConn) protocols.Pipe(mikaConn, s.conn) s.closed = true return }
func listen(serverInfo *utils.ServerConf) { nl, err := net.Listen("tcp", fmt.Sprintf("%s:%d", serverInfo.Address, serverInfo.Port)) if err != nil { utils.Fatalf("Create server error %s", err) } utils.Infof("Listen on %d\n", serverInfo.Port) cg := mika.NewCryptoGenerator(serverInfo.Method, serverInfo.Password) for { c, err := nl.Accept() if err != nil { utils.Errorf("Accept connection error %s", err) continue } go func() { tcpConn := &tcp.Conn{c, time.Duration(serverInfo.Timeout) * time.Second} handle(tcpConn, cg) }() } }