mirror of
				https://github.com/ergochat/ergo.git
				synced 2025-11-04 07:47:25 +01:00 
			
		
		
		
	support unix domain sockets
This commit is contained in:
		
							parent
							
								
									bec39ee8cb
								
							
						
					
					
						commit
						2a7f055ef3
					
				@ -33,6 +33,7 @@ const (
 | 
			
		||||
var (
 | 
			
		||||
	// ErrNickAlreadySet is a weird error that's sent when the server's consistency has been compromised.
 | 
			
		||||
	ErrNickAlreadySet = errors.New("Nickname is already set")
 | 
			
		||||
	LoopbackIP        = net.ParseIP("127.0.0.1")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Client is an IRC client.
 | 
			
		||||
@ -64,7 +65,7 @@ type Client struct {
 | 
			
		||||
	nickMaskCasefolded string
 | 
			
		||||
	nickMaskString     string // cache for nickmask string since it's used with lots of replies
 | 
			
		||||
	operName           string
 | 
			
		||||
	proxiedIP          string // actual remote IP if using the PROXY protocol
 | 
			
		||||
	proxiedIP          net.IP // actual remote IP if using the PROXY protocol
 | 
			
		||||
	quitMessage        string
 | 
			
		||||
	rawHostname        string
 | 
			
		||||
	realname           string
 | 
			
		||||
@ -111,7 +112,7 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
 | 
			
		||||
		// error is not useful to us here anyways so we can ignore it
 | 
			
		||||
		client.certfp, _ = client.socket.CertFP()
 | 
			
		||||
	}
 | 
			
		||||
	if server.checkIdent {
 | 
			
		||||
	if server.checkIdent && !utils.AddrIsUnix(conn.RemoteAddr()) {
 | 
			
		||||
		_, serverPortString, err := net.SplitHostPort(conn.LocalAddr().String())
 | 
			
		||||
		serverPort, _ := strconv.Atoi(serverPortString)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@ -146,19 +147,18 @@ func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
 | 
			
		||||
 | 
			
		||||
// IP returns the IP address of this client.
 | 
			
		||||
func (client *Client) IP() net.IP {
 | 
			
		||||
	if client.proxiedIP != "" {
 | 
			
		||||
		return net.ParseIP(client.proxiedIP)
 | 
			
		||||
	if client.proxiedIP != nil {
 | 
			
		||||
		return client.proxiedIP
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return net.ParseIP(utils.IPString(client.socket.conn.RemoteAddr()))
 | 
			
		||||
	if ip := utils.AddrToIP(client.socket.conn.RemoteAddr()); ip != nil {
 | 
			
		||||
		return ip
 | 
			
		||||
	}
 | 
			
		||||
	// unix domain socket that hasn't issued PROXY/WEBIRC yet. YOLO
 | 
			
		||||
	return LoopbackIP
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IPString returns the IP address of this client as a string.
 | 
			
		||||
func (client *Client) IPString() string {
 | 
			
		||||
	if client.proxiedIP != "" {
 | 
			
		||||
		return client.proxiedIP
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ip := client.IP().String()
 | 
			
		||||
	if 0 < len(ip) && ip[0] == ':' {
 | 
			
		||||
		ip = "0" + ip
 | 
			
		||||
@ -581,7 +581,7 @@ func (client *Client) AllNickmasks() []string {
 | 
			
		||||
		masks = append(masks, mask)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mask2, err := Casefold(fmt.Sprintf("%s!%s@%s", client.nick, client.username, utils.IPString(client.socket.conn.RemoteAddr())))
 | 
			
		||||
	mask2, err := Casefold(fmt.Sprintf("%s!%s@%s", client.nick, client.username, client.IPString()))
 | 
			
		||||
	if err == nil && mask2 != mask {
 | 
			
		||||
		masks = append(masks, mask2)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -38,10 +38,34 @@ func (wc *webircConfig) Populate() (err error) {
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isGatewayAllowed(addr net.Addr, gatewaySpec string) bool {
 | 
			
		||||
	// "localhost" includes any loopback IP or unix domain socket
 | 
			
		||||
	if gatewaySpec == "localhost" {
 | 
			
		||||
		return utils.AddrIsLocal(addr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ip := utils.AddrToIP(addr)
 | 
			
		||||
	if ip == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// exact IP match
 | 
			
		||||
	if ip.String() == gatewaySpec {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// CIDR match
 | 
			
		||||
	_, gatewayNet, err := net.ParseCIDR(gatewaySpec)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return gatewayNet.Contains(ip)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WEBIRC <password> <gateway> <hostname> <ip> [:flag1 flag2=x flag3]
 | 
			
		||||
func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
 | 
			
		||||
	// only allow unregistered clients to use this command
 | 
			
		||||
	if client.registered || client.proxiedIP != "" {
 | 
			
		||||
	if client.registered || client.proxiedIP != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -68,11 +92,9 @@ func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clientAddress := utils.IPString(client.socket.conn.RemoteAddr())
 | 
			
		||||
	clientHostname := client.hostname
 | 
			
		||||
	for _, info := range server.WebIRCConfig() {
 | 
			
		||||
		for _, address := range info.Hosts {
 | 
			
		||||
			if clientHostname == address || clientAddress == address {
 | 
			
		||||
		for _, gateway := range info.Hosts {
 | 
			
		||||
			if isGatewayAllowed(client.socket.conn.RemoteAddr(), gateway) {
 | 
			
		||||
				// confirm password and/or fingerprint
 | 
			
		||||
				givenPassword := msg.Params[0]
 | 
			
		||||
				if 0 < len(info.Password) && passwd.ComparePasswordString(info.Password, givenPassword) != nil {
 | 
			
		||||
@ -96,14 +118,12 @@ func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
 | 
			
		||||
// http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
 | 
			
		||||
func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
 | 
			
		||||
	// only allow unregistered clients to use this command
 | 
			
		||||
	if client.registered || client.proxiedIP != "" {
 | 
			
		||||
	if client.registered || client.proxiedIP != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clientAddress := utils.IPString(client.socket.conn.RemoteAddr())
 | 
			
		||||
	clientHostname := client.hostname
 | 
			
		||||
	for _, address := range server.ProxyAllowedFrom() {
 | 
			
		||||
		if clientHostname == address || clientAddress == address {
 | 
			
		||||
	for _, gateway := range server.ProxyAllowedFrom() {
 | 
			
		||||
		if isGatewayAllowed(client.socket.conn.RemoteAddr(), gateway) {
 | 
			
		||||
			proxiedIP := msg.Params[1]
 | 
			
		||||
 | 
			
		||||
			// assume PROXY connections are always secure
 | 
			
		||||
@ -130,7 +150,7 @@ func (client *Client) ApplyProxiedIP(proxiedIP string, tls bool) (exiting bool)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// given IP is sane! override the client's current IP
 | 
			
		||||
	client.proxiedIP = proxiedIP
 | 
			
		||||
	client.proxiedIP = parsedProxiedIP
 | 
			
		||||
	client.rawHostname = utils.LookupHostname(proxiedIP)
 | 
			
		||||
	client.hostname = client.rawHostname
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -267,19 +267,15 @@ func (server *Server) Run() {
 | 
			
		||||
 | 
			
		||||
func (server *Server) acceptClient(conn clientConn) {
 | 
			
		||||
	// check IP address
 | 
			
		||||
	ipaddr := net.ParseIP(utils.IPString(conn.Conn.RemoteAddr()))
 | 
			
		||||
	if ipaddr == nil {
 | 
			
		||||
		conn.Conn.Write([]byte(couldNotParseIPMsg))
 | 
			
		||||
		conn.Conn.Close()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	isBanned, banMsg := server.checkBans(ipaddr)
 | 
			
		||||
	if isBanned {
 | 
			
		||||
		// this might not show up properly on some clients, but our objective here is just to close the connection out before it has a load impact on us
 | 
			
		||||
		conn.Conn.Write([]byte(fmt.Sprintf(errorMsg, banMsg)))
 | 
			
		||||
		conn.Conn.Close()
 | 
			
		||||
		return
 | 
			
		||||
	ipaddr := utils.AddrToIP(conn.Conn.RemoteAddr())
 | 
			
		||||
	if ipaddr != nil {
 | 
			
		||||
		isBanned, banMsg := server.checkBans(ipaddr)
 | 
			
		||||
		if isBanned {
 | 
			
		||||
			// this might not show up properly on some clients, but our objective here is just to close the connection out before it has a load impact on us
 | 
			
		||||
			conn.Conn.Write([]byte(fmt.Sprintf(errorMsg, banMsg)))
 | 
			
		||||
			conn.Conn.Close()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	server.logger.Debug("localconnect-ip", fmt.Sprintf("Client connecting from %v", ipaddr))
 | 
			
		||||
@ -336,7 +332,23 @@ func (server *Server) checkBans(ipaddr net.IP) (banned bool, message string) {
 | 
			
		||||
// createListener starts the given listeners.
 | 
			
		||||
func (server *Server) createListener(addr string, tlsConfig *tls.Config) *ListenerWrapper {
 | 
			
		||||
	// make listener
 | 
			
		||||
	listener, err := net.Listen("tcp", addr)
 | 
			
		||||
	var listener net.Listener
 | 
			
		||||
	var err error
 | 
			
		||||
	optional_unix_prefix := "unix:"
 | 
			
		||||
	optional_prefix_len := len(optional_unix_prefix)
 | 
			
		||||
	if len(addr) >= optional_prefix_len && strings.ToLower(addr[0:optional_prefix_len]) == optional_unix_prefix {
 | 
			
		||||
		addr = addr[optional_prefix_len:]
 | 
			
		||||
		if len(addr) == 0 || addr[0] != '/' {
 | 
			
		||||
			log.Fatal("Bad unix socket address", addr)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(addr) > 0 && addr[0] == '/' {
 | 
			
		||||
		// https://stackoverflow.com/a/34881585
 | 
			
		||||
		os.Remove(addr)
 | 
			
		||||
		listener, err = net.Listen("unix", addr)
 | 
			
		||||
	} else {
 | 
			
		||||
		listener, err = net.Listen("tcp", addr)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(server, "listen error: ", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,9 @@ func IPString(addr net.Addr) string {
 | 
			
		||||
 | 
			
		||||
// AddrLookupHostname returns the hostname (if possible) or address for the given `net.Addr`.
 | 
			
		||||
func AddrLookupHostname(addr net.Addr) string {
 | 
			
		||||
	if AddrIsUnix(addr) {
 | 
			
		||||
		return "localhost"
 | 
			
		||||
	}
 | 
			
		||||
	return LookupHostname(IPString(addr))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -30,10 +33,22 @@ func AddrIsLocal(addr net.Addr) bool {
 | 
			
		||||
	if tcpaddr, ok := addr.(*net.TCPAddr); ok {
 | 
			
		||||
		return tcpaddr.IP.IsLoopback()
 | 
			
		||||
	}
 | 
			
		||||
	if _, ok := addr.(*net.UnixAddr); ok {
 | 
			
		||||
		return true
 | 
			
		||||
	_, ok := addr.(*net.UnixAddr)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddrToIP returns the IP address for a net.Addr, or nil if it's a unix domain socket.
 | 
			
		||||
func AddrToIP(addr net.Addr) net.IP {
 | 
			
		||||
	if tcpaddr, ok := addr.(*net.TCPAddr); ok {
 | 
			
		||||
		return tcpaddr.IP
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddrIsUnix returns whether the address is a unix domain socket.
 | 
			
		||||
func AddrIsUnix(addr net.Addr) bool {
 | 
			
		||||
	_, ok := addr.(*net.UnixAddr)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LookupHostname returns the hostname for `addr` if it has one. Otherwise, just returns `addr`.
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,8 @@ server:
 | 
			
		||||
        - "127.0.0.1:6668"
 | 
			
		||||
        - "[::1]:6668"
 | 
			
		||||
        - ":6697" # ssl port
 | 
			
		||||
        # unix domain socket for proxying:
 | 
			
		||||
        # - "/tmp/oragono_sock"
 | 
			
		||||
 | 
			
		||||
    # tls listeners
 | 
			
		||||
    tls-listeners:
 | 
			
		||||
@ -59,11 +61,12 @@ server:
 | 
			
		||||
    #motd-formatting: true
 | 
			
		||||
 | 
			
		||||
    # addresses/hostnames the PROXY command can be used from
 | 
			
		||||
    # this should be restricted to 127.0.0.1 and localhost at most
 | 
			
		||||
    # this should be restricted to 127.0.0.1/8 and localhost at most
 | 
			
		||||
    # you should also add these addresses to the connection limits and throttling exemption lists
 | 
			
		||||
    proxy-allowed-from:
 | 
			
		||||
        # - localhost
 | 
			
		||||
        # - "127.0.0.1"
 | 
			
		||||
        # - "127.0.0.1/8"
 | 
			
		||||
 | 
			
		||||
    # controls the use of the WEBIRC command (by IRC<->web interfaces, bouncers and similar)
 | 
			
		||||
    webirc:
 | 
			
		||||
@ -79,6 +82,7 @@ server:
 | 
			
		||||
            hosts:
 | 
			
		||||
                # - localhost
 | 
			
		||||
                # - "127.0.0.1"
 | 
			
		||||
                # - "127.0.0.1/8"
 | 
			
		||||
                # - "0::1"
 | 
			
		||||
 | 
			
		||||
    # maximum length of clients' sendQ in bytes
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user