Authentication-Results: mail-b.sr.ht; dkim=pass header.d=gmail.com header.i=@gmail.com Received: from mail-wr1-f52.google.com (mail-wr1-f52.google.com [209.85.221.52]) by mail-b.sr.ht (Postfix) with ESMTPS id 6DB2511F030 for <~emersion/soju-dev@lists.sr.ht>; Wed, 19 Oct 2022 08:48:23 +0000 (UTC) Received: by mail-wr1-f52.google.com with SMTP id f11so27936812wrm.6 for <~emersion/soju-dev@lists.sr.ht>; Wed, 19 Oct 2022 01:48:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=BwCHRZliJrz4WEzeN0favCCoMs89MmDHVyXxTq5kpng=; b=nkrxJBJZV505ZhvB6P9a+O9XEjd9PxrAcGaM6SxUTHAuJOozPLlPF3t40dxEd9C+WI nLL0dmh4MIygEw2FJdOjJ4sh3OUAdaIVzkCmmcUScmnnbILx8N3N0C2skp5GANpI0Orr Vbj1dFKwpvMfxy4uW45oTpUfArEb9xZJSMsfMfasLzTk9FAZOpb7F0RyFKMhXYS68Zxu UjOpZg5M8Cnq2zl/Y8tyP57ObKVkNO/Z7NRrlDOVLViZKeTRwGMLZ9z9gTEx34FV6kZs 79Bx45L0DeCyEpRN2qE3GM9kJP9mB635nVDb+HZA23Dpiiv3/dOWN58iXoQAXFvYT3ZF 9mLQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=BwCHRZliJrz4WEzeN0favCCoMs89MmDHVyXxTq5kpng=; b=K0BGDTAUqr5g4fOdqFpP1Q7tWc8gVtwZIOArhDJMP7SavBI87wKdD4UTV4zqMhEZzT 98kttqCI61dkuwA4bO1Rwsd3XjClm90qg7j8Lo8AM0OXBZJvKiXOr+yuUFraN28VpIxX jat3KW7hSJp45byqFdR8TJNMeEEtM4D5+8jPohtSKWSMCOQpCVdoSkNASyWXtJmp0fje 1S2UHSvkko0cgUmgta2nIoAslsYy+/C3WL4U1jhFlo7EEYs5wHwtO8v1wEXTRc8h+BMl tzQkLbP9sOxZslRWq36XSS9ZC9jnPPvgl3nBV+cheOBGl/pXR4dDfY8h+fmSPFLwIXPx 9fzw== X-Gm-Message-State: ACrzQf0vrAdV2j5D7cT3V9qLLFcQWx901ULlXC67YLLdD/KLc8zkxkBr Ca6j/SANstVQuCcx16Yin+M9GYRZ+A4= X-Google-Smtp-Source: AMsMyM47NbF+9QufjcVbOIrG5gS1sjM0G92rcGUOavt1S0iT1gFYBabmM9X/drIn2Q2mYTXnvZ9F+Q== X-Received: by 2002:a5d:59a2:0:b0:22f:f2eb:ea86 with SMTP id p2-20020a5d59a2000000b0022ff2ebea86mr4207859wrr.635.1666169302269; Wed, 19 Oct 2022 01:48:22 -0700 (PDT) Received: from localhost (adsl-209.91.140.88.tellas.gr. [91.140.88.209]) by smtp.gmail.com with ESMTPSA id r9-20020a05600c458900b003b47b913901sm975013wmo.1.2022.10.19.01.48.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Oct 2022 01:48:21 -0700 (PDT) From: Julio B To: ~emersion/soju-dev@lists.sr.ht Cc: Julio B Subject: [PATCH v2] Accept proxy protocol on unix sockets Date: Wed, 19 Oct 2022 11:47:51 +0300 Message-Id: <20221019084751.48995-1-julio.bacel@gmail.com> X-Mailer: git-send-email 2.38.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit --- Now soju accepts PROXY only on specified unix sockets. Below are some testing commands that i used. Example soju configuration ... listen unix:///tmp/sojuaccept.socket listen unix:///tmp/soju.socket accept-proxy-from unix:///tmp/sojuaccept.socket ... Quick testing soju rejects PROXY $ echo -ne "PROXY TCP4 27.13.13.12 10.10.10.10 44554 6697\r\nQUIT\r\n" | socat unix-client:/tmp/soju.socket - soju must accept $ echo -ne "PROXY TCP4 27.13.13.12 10.10.10.10 44554 6697\r\nQUIT\r\n" | socat unix-client:/tmp/sojuaccept.socket - Example usage behind reverse proxy nginx.conf ... stream { server { listen 55555; proxy_pass unix:/tmp/sojuaccept.socket; proxy_protocol on; } } ... soju accepts PROXY from nginx. Attackers PROXY is parsed as a common irc command $ echo -ne "PROXY TCP4 27.13.13.12 10.10.10.10 43215 6697\r\nQUIT\r\n" | socat tcp-connect:soju.irc:55555 - cmd/soju/main.go | 8 +++++--- config/config.go | 23 ++++++++++++++++++++--- doc/soju.1.scd | 10 ++++++++-- server.go | 1 + 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/cmd/soju/main.go b/cmd/soju/main.go index 0094381..7e57582 100644 --- a/cmd/soju/main.go +++ b/cmd/soju/main.go @@ -89,6 +89,7 @@ func loadConfig() (*config.Server, *soju.Config, error) { LogPath: raw.MsgStore.Source, HTTPOrigins: raw.HTTPOrigins, AcceptProxyIPs: raw.AcceptProxyIPs, + AcceptProxyUnix: raw.AcceptProxyUnix, MaxUserNetworks: raw.MaxUserNetworks, UpstreamUserIPs: raw.UpstreamUserIPs, MOTD: motd, @@ -345,10 +346,11 @@ func proxyProtoListener(ln net.Listener, srv *soju.Server) net.Listener { Listener: ln, Policy: func(upstream net.Addr) (proxyproto.Policy, error) { tcpAddr, ok := upstream.(*net.TCPAddr) - if !ok { - return proxyproto.IGNORE, nil + if ok && srv.Config().AcceptProxyIPs.Contains(tcpAddr.IP) { + return proxyproto.USE, nil } - if srv.Config().AcceptProxyIPs.Contains(tcpAddr.IP) { + unixAddr, ok := ln.Addr().(*net.UnixAddr) + if ok && srv.Config().AcceptProxyUnix.Contains(unixAddr.String()) { return proxyproto.USE, nil } return proxyproto.IGNORE, nil diff --git a/config/config.go b/config/config.go index 25233dd..7b3fe13 100644 --- a/config/config.go +++ b/config/config.go @@ -5,6 +5,7 @@ import ( "net" "os" "strconv" + "strings" "git.sr.ht/~emersion/go-scfg" ) @@ -32,6 +33,17 @@ var loopbackIPs = IPSet{ }, } +type UnixSet []string + +func (set UnixSet) Contains(socket string) bool { + for _, s := range set { + if s == "unix" || strings.TrimPrefix(s, "unix://") == socket { + return true + } + } + return false +} + type TLS struct { CertPath, KeyPath string } @@ -54,8 +66,9 @@ type Server struct { DB DB MsgStore MsgStore - HTTPOrigins []string - AcceptProxyIPs IPSet + HTTPOrigins []string + AcceptProxyIPs IPSet + AcceptProxyUnix UnixSet MaxUserNetworks int UpstreamUserIPs []*net.IPNet @@ -135,13 +148,17 @@ func parse(cfg scfg.Block) (*Server, error) { } case "http-origin": srv.HTTPOrigins = d.Params - case "accept-proxy-ip": + case "accept-proxy-from", "accept-proxy-ip": srv.AcceptProxyIPs = nil for _, s := range d.Params { if s == "localhost" { srv.AcceptProxyIPs = append(srv.AcceptProxyIPs, loopbackIPs...) continue } + if strings.HasPrefix(s, "unix") { + srv.AcceptProxyUnix = append(srv.AcceptProxyUnix, s) + continue + } _, n, err := net.ParseCIDR(s) if err != nil { return nil, fmt.Errorf("directive %q: failed to parse CIDR: %v", d.Name, err) diff --git a/doc/soju.1.scd b/doc/soju.1.scd index b5e398e..080c446 100644 --- a/doc/soju.1.scd +++ b/doc/soju.1.scd @@ -145,14 +145,20 @@ The following directives are supported: By default, only the request host is authorized. Use this directive to enable cross-origin WebSockets. -*accept-proxy-ip* +*accept-proxy-from* Allow the specified IPs to act as a proxy. Proxys have the ability to overwrite the remote and local connection addresses (via the PROXY protocol, the Forwarded HTTP header field defined in RFC 7239 or the X-Forwarded-\* HTTP header fields). The special name "localhost" accepts the loopback addresses 127.0.0.0/8 and ::1/128. - By default, all IPs are rejected. + The special name "unix" accepts PROXY protocol on all unix sockets that + soju is listening on. Use the more specific format "unix:///path/to/socket" + to accept just on that socket. + + By default, all IPs and sockets are rejected. + + (_accept-proxy-ip_ is a deprecated alias for this directive.) *max-user-networks* Maximum number of networks per user. By default, there is no limit. diff --git a/server.go b/server.go index dc209a3..1cad9f1 100644 --- a/server.go +++ b/server.go @@ -138,6 +138,7 @@ type Config struct { LogPath string HTTPOrigins []string AcceptProxyIPs config.IPSet + AcceptProxyUnix config.UnixSet MaxUserNetworks int MOTD string UpstreamUserIPs []*net.IPNet -- 2.38.0