Changeset 705 in code for trunk


Ignore:
Timestamp:
Nov 17, 2021, 2:07:58 PM (4 years ago)
Author:
contact
Message:

Add per-user IP addresses

The new upstream-user-ip directive allows bouncer operators to
assign one IP address per user.

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/cmd/soju/main.go

    r694 r705  
    9494                MaxUserNetworks: raw.MaxUserNetworks,
    9595                MultiUpstream:   raw.MultiUpstream,
     96                UpstreamUserIPs: raw.UpstreamUserIPs,
    9697                Debug:           debug,
    9798                MOTD:            motd,
  • trunk/config/config.go

    r694 r705  
    5353        MaxUserNetworks int
    5454        MultiUpstream   bool
     55        UpstreamUserIPs []*net.IPNet
    5556}
    5657
     
    151152                        }
    152153                        srv.MultiUpstream = v
     154                case "upstream-user-ip":
     155                        if len(srv.UpstreamUserIPs) > 0 {
     156                                return nil, fmt.Errorf("directive %q: can only be specified once", d.Name)
     157                        }
     158                        var hasIPv4, hasIPv6 bool
     159                        for _, s := range d.Params {
     160                                _, n, err := net.ParseCIDR(s)
     161                                if err != nil {
     162                                        return nil, fmt.Errorf("directive %q: failed to parse CIDR: %v", d.Name, err)
     163                                }
     164                                if n.IP.To4() == nil {
     165                                        if hasIPv6 {
     166                                                return nil, fmt.Errorf("directive %q: found two IPv6 CIDRs", d.Name)
     167                                        }
     168                                        hasIPv6 = true
     169                                } else {
     170                                        if hasIPv4 {
     171                                                return nil, fmt.Errorf("directive %q: found two IPv4 CIDRs", d.Name)
     172                                        }
     173                                        hasIPv4 = true
     174                                }
     175                                srv.UpstreamUserIPs = append(srv.UpstreamUserIPs, n)
     176                        }
    153177                default:
    154178                        return nil, fmt.Errorf("unknown directive %q", d.Name)
  • trunk/doc/soju.1.scd

    r694 r705  
    157157        mode is enabled.
    158158
     159*upstream-user-ip* <cidr...>
     160        Enable per-user IP addresses. One IPv4 range and/or one IPv6 range can be
     161        specified in CIDR notation. One IP address per range will be assigned to
     162        each user and will be used as the source address when connecting to an
     163        upstream network.
     164
     165        This can be useful to avoid having the whole bouncer banned from an upstream
     166        network because of one malicious user.
     167
    159168# IRC SERVICE
    160169
  • trunk/server.go

    r704 r705  
    6565        MultiUpstream   bool
    6666        MOTD            string
     67        UpstreamUserIPs []*net.IPNet
    6768}
    6869
  • trunk/upstream.go

    r685 r705  
    141141                }
    142142
     143                dialer.LocalAddr, err = network.user.localTCPAddrForHost(host)
     144                if err != nil {
     145                        return nil, fmt.Errorf("failed to pick local IP for remote host %q: %v", host, err)
     146                }
     147
    143148                logger.Printf("connecting to TLS server at address %q", addr)
    144149
     
    175180        case "irc+insecure":
    176181                addr := u.Host
    177                 if _, _, err := net.SplitHostPort(addr); err != nil {
    178                         addr = addr + ":6667"
     182                host, _, err := net.SplitHostPort(addr)
     183                if err != nil {
     184                        host = u.Host
     185                        addr = u.Host + ":6667"
     186                }
     187
     188                dialer.LocalAddr, err = network.user.localTCPAddrForHost(host)
     189                if err != nil {
     190                        return nil, fmt.Errorf("failed to pick local IP for remote host %q: %v", host, err)
    179191                }
    180192
  • trunk/user.go

    r704 r705  
    77        "encoding/hex"
    88        "fmt"
     9        "math/big"
     10        "net"
    911        "time"
    1012
     
    957959        return !isMem
    958960}
     961
     962// localAddrForHost returns the local address to use when connecting to host.
     963// A nil address is returned when the OS should automatically pick one.
     964func (u *user) localTCPAddrForHost(host string) (*net.TCPAddr, error) {
     965        upstreamUserIPs := u.srv.Config().UpstreamUserIPs
     966        if len(upstreamUserIPs) == 0 {
     967                return nil, nil
     968        }
     969
     970        ips, err := net.LookupIP(host)
     971        if err != nil {
     972                return nil, err
     973        }
     974
     975        wantIPv6 := false
     976        for _, ip := range ips {
     977                if ip.To4() == nil {
     978                        wantIPv6 = true
     979                        break
     980                }
     981        }
     982
     983        var ipNet *net.IPNet
     984        for _, in := range upstreamUserIPs {
     985                if wantIPv6 == (in.IP.To4() == nil) {
     986                        ipNet = in
     987                        break
     988                }
     989        }
     990        if ipNet == nil {
     991                return nil, nil
     992        }
     993
     994        var ipInt big.Int
     995        ipInt.SetBytes(ipNet.IP)
     996        ipInt.Add(&ipInt, big.NewInt(u.ID+1))
     997        ip := net.IP(ipInt.Bytes())
     998        if !ipNet.Contains(ip) {
     999                return nil, fmt.Errorf("IP network %v too small", ipNet)
     1000        }
     1001
     1002        return &net.TCPAddr{IP: ip}, nil
     1003}
Note: See TracChangeset for help on using the changeset viewer.