Skip to content
Snippets Groups Projects
Select Git revision
  • master default protected
1 result

main.go

Blame
  • main.go 2.85 KiB
    package main
    
    import (
    	"bufio"
    	"crypto/tls"
    	"encoding/binary"
    	"flag"
    	"fmt"
    	"net"
    )
    
    const ProtocolMagic uint32 = 0x42b33f00
    
    const ProtocolFeatureTls uint8 = 0x01
    const ProtocolFeatureCompression uint8 = 0x02
    
    const ProtocolDatastream uint32 = 0x02
    
    type connection struct {
    	hostname   string
    	socket     net.Conn
    	tlsSocket  *tls.Conn
    	readWriter *bufio.ReadWriter
    	buffer     []byte
    }
    
    func makeConnection(address string, port int) connection {
    	socket, err := net.Dial("tcp", fmt.Sprintf("%s:%d", address, port))
    	if err != nil {
    		panic(err.Error())
    	}
    
    	return connection{
    		hostname: address,
    		socket:   socket,
    		readWriter: bufio.NewReadWriter(
    			bufio.NewReader(socket),
    			bufio.NewWriter(socket),
    		),
    		buffer: make([]byte, 4),
    	}
    }
    
    func (c *connection) write(data uint32) {
    	binary.BigEndian.PutUint32(c.buffer, data)
    	_, err := c.readWriter.Write(c.buffer)
    	if err != nil {
    		panic(err.Error())
    	}
    }
    
    func (c *connection) read(len int) []byte {
    	buffer := make([]byte, len)
    	_, err := c.readWriter.Read(buffer)
    	if err != nil {
    		panic(err.Error())
    	}
    	return buffer
    }
    
    func (c *connection) flush() {
    	err := c.readWriter.Flush()
    	if err != nil {
    		panic(err.Error())
    	}
    }
    
    func (c *connection) withTLS(verify bool) {
    	config := &tls.Config{
    		ServerName:         c.hostname,
    		InsecureSkipVerify: !verify,
    	}
    	c.tlsSocket = tls.Client(c.socket, config)
    	c.readWriter = bufio.NewReadWriter(
    		bufio.NewReader(c.tlsSocket),
    		bufio.NewWriter(c.tlsSocket),
    	)
    	err := c.tlsSocket.Handshake()
    	if err != nil {
    		panic(err.Error())
    	}
    }
    
    func (c *connection) tlsState() *tls.ConnectionState {
    	if c.tlsSocket != nil {
    		state := c.tlsSocket.ConnectionState()
    		return &state
    	} else {
    		return nil
    	}
    }
    
    func (c *connection) close() {
    	_ = c.readWriter.Flush()
    	_ = c.tlsSocket.Close()
    	_ = c.socket.Close()
    }
    
    type protocolInfo struct {
    	flagTLS         bool
    	flagCompression bool
    	data            uint16
    	version         uint8
    }
    
    func parseProtocolInfo(data []byte) protocolInfo {
    	rawFeatures := data[0]
    	rawData := data[1:3]
    	rawVersion := data[3]
    
    	return protocolInfo{
    		rawFeatures&ProtocolFeatureTls != 0,
    		rawFeatures&ProtocolFeatureCompression != 0,
    		binary.BigEndian.Uint16(rawData),
    		rawVersion,
    	}
    }
    
    func main() {
    	hostname := flag.String("hostname", "", "address of server to connect to")
    	port := flag.Int("port", 4242, "port of server to connect to")
    	flag.Parse()
    
    	conn := makeConnection(*hostname, *port)
    	conn.write(ProtocolMagic | uint32(ProtocolFeatureTls))
    	supportedProtocols := []uint32{
    		ProtocolDatastream,
    	}
    	for _, protocol := range supportedProtocols {
    		conn.write(protocol)
    	}
    	conn.write(1 << 31)
    	conn.flush()
    	protocolInfo := parseProtocolInfo(conn.read(4))
    	if protocolInfo.flagTLS {
    		conn.withTLS(false)
    	}
    	if state := conn.tlsState(); state != nil {
    		for _, cert := range state.PeerCertificates {
    			println(cert.NotAfter.String())
    		}
    	}
    	conn.close()
    }