mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-22 11:59:40 +01:00
support unix domain sockets
This commit is contained in:
parent
bec39ee8cb
commit
2a7f055ef3
@ -33,6 +33,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
// ErrNickAlreadySet is a weird error that's sent when the server's consistency has been compromised.
|
// ErrNickAlreadySet is a weird error that's sent when the server's consistency has been compromised.
|
||||||
ErrNickAlreadySet = errors.New("Nickname is already set")
|
ErrNickAlreadySet = errors.New("Nickname is already set")
|
||||||
|
LoopbackIP = net.ParseIP("127.0.0.1")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client is an IRC client.
|
// Client is an IRC client.
|
||||||
@ -64,7 +65,7 @@ type Client struct {
|
|||||||
nickMaskCasefolded string
|
nickMaskCasefolded string
|
||||||
nickMaskString string // cache for nickmask string since it's used with lots of replies
|
nickMaskString string // cache for nickmask string since it's used with lots of replies
|
||||||
operName string
|
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
|
quitMessage string
|
||||||
rawHostname string
|
rawHostname string
|
||||||
realname 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
|
// error is not useful to us here anyways so we can ignore it
|
||||||
client.certfp, _ = client.socket.CertFP()
|
client.certfp, _ = client.socket.CertFP()
|
||||||
}
|
}
|
||||||
if server.checkIdent {
|
if server.checkIdent && !utils.AddrIsUnix(conn.RemoteAddr()) {
|
||||||
_, serverPortString, err := net.SplitHostPort(conn.LocalAddr().String())
|
_, serverPortString, err := net.SplitHostPort(conn.LocalAddr().String())
|
||||||
serverPort, _ := strconv.Atoi(serverPortString)
|
serverPort, _ := strconv.Atoi(serverPortString)
|
||||||
if err != nil {
|
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.
|
// IP returns the IP address of this client.
|
||||||
func (client *Client) IP() net.IP {
|
func (client *Client) IP() net.IP {
|
||||||
if client.proxiedIP != "" {
|
if client.proxiedIP != nil {
|
||||||
return net.ParseIP(client.proxiedIP)
|
return client.proxiedIP
|
||||||
}
|
}
|
||||||
|
if ip := utils.AddrToIP(client.socket.conn.RemoteAddr()); ip != nil {
|
||||||
return net.ParseIP(utils.IPString(client.socket.conn.RemoteAddr()))
|
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.
|
// IPString returns the IP address of this client as a string.
|
||||||
func (client *Client) IPString() string {
|
func (client *Client) IPString() string {
|
||||||
if client.proxiedIP != "" {
|
|
||||||
return client.proxiedIP
|
|
||||||
}
|
|
||||||
|
|
||||||
ip := client.IP().String()
|
ip := client.IP().String()
|
||||||
if 0 < len(ip) && ip[0] == ':' {
|
if 0 < len(ip) && ip[0] == ':' {
|
||||||
ip = "0" + ip
|
ip = "0" + ip
|
||||||
@ -581,7 +581,7 @@ func (client *Client) AllNickmasks() []string {
|
|||||||
masks = append(masks, mask)
|
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 {
|
if err == nil && mask2 != mask {
|
||||||
masks = append(masks, mask2)
|
masks = append(masks, mask2)
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,34 @@ func (wc *webircConfig) Populate() (err error) {
|
|||||||
return err
|
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]
|
// WEBIRC <password> <gateway> <hostname> <ip> [:flag1 flag2=x flag3]
|
||||||
func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
func webircHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||||
// only allow unregistered clients to use this command
|
// only allow unregistered clients to use this command
|
||||||
if client.registered || client.proxiedIP != "" {
|
if client.registered || client.proxiedIP != nil {
|
||||||
return false
|
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 _, info := range server.WebIRCConfig() {
|
||||||
for _, address := range info.Hosts {
|
for _, gateway := range info.Hosts {
|
||||||
if clientHostname == address || clientAddress == address {
|
if isGatewayAllowed(client.socket.conn.RemoteAddr(), gateway) {
|
||||||
// confirm password and/or fingerprint
|
// confirm password and/or fingerprint
|
||||||
givenPassword := msg.Params[0]
|
givenPassword := msg.Params[0]
|
||||||
if 0 < len(info.Password) && passwd.ComparePasswordString(info.Password, givenPassword) != nil {
|
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
|
// http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
|
||||||
func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
func proxyHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
||||||
// only allow unregistered clients to use this command
|
// only allow unregistered clients to use this command
|
||||||
if client.registered || client.proxiedIP != "" {
|
if client.registered || client.proxiedIP != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
clientAddress := utils.IPString(client.socket.conn.RemoteAddr())
|
for _, gateway := range server.ProxyAllowedFrom() {
|
||||||
clientHostname := client.hostname
|
if isGatewayAllowed(client.socket.conn.RemoteAddr(), gateway) {
|
||||||
for _, address := range server.ProxyAllowedFrom() {
|
|
||||||
if clientHostname == address || clientAddress == address {
|
|
||||||
proxiedIP := msg.Params[1]
|
proxiedIP := msg.Params[1]
|
||||||
|
|
||||||
// assume PROXY connections are always secure
|
// 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
|
// given IP is sane! override the client's current IP
|
||||||
client.proxiedIP = proxiedIP
|
client.proxiedIP = parsedProxiedIP
|
||||||
client.rawHostname = utils.LookupHostname(proxiedIP)
|
client.rawHostname = utils.LookupHostname(proxiedIP)
|
||||||
client.hostname = client.rawHostname
|
client.hostname = client.rawHostname
|
||||||
|
|
||||||
|
@ -267,19 +267,15 @@ func (server *Server) Run() {
|
|||||||
|
|
||||||
func (server *Server) acceptClient(conn clientConn) {
|
func (server *Server) acceptClient(conn clientConn) {
|
||||||
// check IP address
|
// check IP address
|
||||||
ipaddr := net.ParseIP(utils.IPString(conn.Conn.RemoteAddr()))
|
ipaddr := utils.AddrToIP(conn.Conn.RemoteAddr())
|
||||||
if ipaddr == nil {
|
if ipaddr != nil {
|
||||||
conn.Conn.Write([]byte(couldNotParseIPMsg))
|
isBanned, banMsg := server.checkBans(ipaddr)
|
||||||
conn.Conn.Close()
|
if isBanned {
|
||||||
return
|
// 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()
|
||||||
isBanned, banMsg := server.checkBans(ipaddr)
|
return
|
||||||
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))
|
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.
|
// createListener starts the given listeners.
|
||||||
func (server *Server) createListener(addr string, tlsConfig *tls.Config) *ListenerWrapper {
|
func (server *Server) createListener(addr string, tlsConfig *tls.Config) *ListenerWrapper {
|
||||||
// make listener
|
// 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 {
|
if err != nil {
|
||||||
log.Fatal(server, "listen error: ", err)
|
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`.
|
// AddrLookupHostname returns the hostname (if possible) or address for the given `net.Addr`.
|
||||||
func AddrLookupHostname(addr net.Addr) string {
|
func AddrLookupHostname(addr net.Addr) string {
|
||||||
|
if AddrIsUnix(addr) {
|
||||||
|
return "localhost"
|
||||||
|
}
|
||||||
return LookupHostname(IPString(addr))
|
return LookupHostname(IPString(addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,10 +33,22 @@ func AddrIsLocal(addr net.Addr) bool {
|
|||||||
if tcpaddr, ok := addr.(*net.TCPAddr); ok {
|
if tcpaddr, ok := addr.(*net.TCPAddr); ok {
|
||||||
return tcpaddr.IP.IsLoopback()
|
return tcpaddr.IP.IsLoopback()
|
||||||
}
|
}
|
||||||
if _, ok := addr.(*net.UnixAddr); ok {
|
_, ok := addr.(*net.UnixAddr)
|
||||||
return true
|
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`.
|
// LookupHostname returns the hostname for `addr` if it has one. Otherwise, just returns `addr`.
|
||||||
|
@ -16,6 +16,8 @@ server:
|
|||||||
- "127.0.0.1:6668"
|
- "127.0.0.1:6668"
|
||||||
- "[::1]:6668"
|
- "[::1]:6668"
|
||||||
- ":6697" # ssl port
|
- ":6697" # ssl port
|
||||||
|
# unix domain socket for proxying:
|
||||||
|
# - "/tmp/oragono_sock"
|
||||||
|
|
||||||
# tls listeners
|
# tls listeners
|
||||||
tls-listeners:
|
tls-listeners:
|
||||||
@ -59,11 +61,12 @@ server:
|
|||||||
#motd-formatting: true
|
#motd-formatting: true
|
||||||
|
|
||||||
# addresses/hostnames the PROXY command can be used from
|
# 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
|
# you should also add these addresses to the connection limits and throttling exemption lists
|
||||||
proxy-allowed-from:
|
proxy-allowed-from:
|
||||||
# - localhost
|
# - localhost
|
||||||
# - "127.0.0.1"
|
# - "127.0.0.1"
|
||||||
|
# - "127.0.0.1/8"
|
||||||
|
|
||||||
# controls the use of the WEBIRC command (by IRC<->web interfaces, bouncers and similar)
|
# controls the use of the WEBIRC command (by IRC<->web interfaces, bouncers and similar)
|
||||||
webirc:
|
webirc:
|
||||||
@ -79,6 +82,7 @@ server:
|
|||||||
hosts:
|
hosts:
|
||||||
# - localhost
|
# - localhost
|
||||||
# - "127.0.0.1"
|
# - "127.0.0.1"
|
||||||
|
# - "127.0.0.1/8"
|
||||||
# - "0::1"
|
# - "0::1"
|
||||||
|
|
||||||
# maximum length of clients' sendQ in bytes
|
# maximum length of clients' sendQ in bytes
|
||||||
|
Loading…
Reference in New Issue
Block a user