You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

gateways.go 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // Copyright (c) 2012-2014 Jeremy Latt
  2. // Copyright (c) 2014-2015 Edmund Huber
  3. // Copyright (c) 2017 Daniel Oaks <daniel@danieloaks.net>
  4. // released under the MIT license
  5. package irc
  6. import (
  7. "errors"
  8. "fmt"
  9. "net"
  10. "strings"
  11. "github.com/oragono/oragono/irc/modes"
  12. "github.com/oragono/oragono/irc/utils"
  13. )
  14. var (
  15. errBadGatewayAddress = errors.New("PROXY/WEBIRC commands are not accepted from this IP address")
  16. errBadProxyLine = errors.New("Invalid PROXY/WEBIRC command")
  17. )
  18. type webircConfig struct {
  19. PasswordString string `yaml:"password"`
  20. Password []byte `yaml:"password-bytes"`
  21. Fingerprint string
  22. Hosts []string
  23. }
  24. // Populate fills out our password or fingerprint.
  25. func (wc *webircConfig) Populate() (err error) {
  26. if wc.Fingerprint == "" && wc.PasswordString == "" {
  27. return ErrNoFingerprintOrPassword
  28. }
  29. if wc.PasswordString != "" {
  30. wc.Password, err = decodeLegacyPasswordHash(wc.PasswordString)
  31. }
  32. return err
  33. }
  34. func isGatewayAllowed(addr net.Addr, gatewaySpec string) bool {
  35. // "localhost" includes any loopback IP or unix domain socket
  36. if gatewaySpec == "localhost" {
  37. return utils.AddrIsLocal(addr)
  38. }
  39. ip := utils.AddrToIP(addr)
  40. if ip == nil {
  41. return false
  42. }
  43. // exact IP match
  44. if ip.String() == gatewaySpec {
  45. return true
  46. }
  47. // CIDR match
  48. _, gatewayNet, err := net.ParseCIDR(gatewaySpec)
  49. if err != nil {
  50. return false
  51. }
  52. return gatewayNet.Contains(ip)
  53. }
  54. // ApplyProxiedIP applies the given IP to the client.
  55. func (client *Client) ApplyProxiedIP(proxiedIP string, tls bool) (success bool) {
  56. // ensure IP is sane
  57. parsedProxiedIP := net.ParseIP(proxiedIP)
  58. if parsedProxiedIP == nil {
  59. client.Quit(fmt.Sprintf(client.t("Proxied IP address is not valid: [%s]"), proxiedIP))
  60. return false
  61. }
  62. // undo any mapping of v4 addresses into the v6 space: https://stackoverflow.com/a/1618259
  63. // this is how a typical stunnel4 deployment on Linux will handle dual-stack
  64. unmappedIP := parsedProxiedIP.To4()
  65. if unmappedIP != nil {
  66. parsedProxiedIP = unmappedIP
  67. }
  68. isBanned, banMsg := client.server.checkBans(parsedProxiedIP)
  69. if isBanned {
  70. client.Quit(banMsg)
  71. return false
  72. }
  73. // given IP is sane! override the client's current IP
  74. rawHostname := utils.LookupHostname(parsedProxiedIP.String())
  75. client.stateMutex.Lock()
  76. client.proxiedIP = parsedProxiedIP
  77. client.rawHostname = rawHostname
  78. client.stateMutex.Unlock()
  79. // nickmask will be updated when the client completes registration
  80. // set tls info
  81. client.certfp = ""
  82. client.SetMode(modes.TLS, tls)
  83. return true
  84. }
  85. // handle the PROXY command: http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
  86. // PROXY must be sent as the first message in the session and has the syntax:
  87. // PROXY TCP[46] SOURCEIP DESTIP SOURCEPORT DESTPORT\r\n
  88. // unfortunately, an ipv6 SOURCEIP can start with a double colon; in this case,
  89. // the message is invalid IRC and can't be parsed normally, hence the special handling.
  90. func handleProxyCommand(server *Server, client *Client, line string) (err error) {
  91. defer func() {
  92. if err != nil {
  93. client.Quit(client.t("Bad or unauthorized PROXY command"))
  94. }
  95. }()
  96. params := strings.Fields(line)
  97. if len(params) != 6 {
  98. return errBadProxyLine
  99. }
  100. for _, gateway := range server.ProxyAllowedFrom() {
  101. if isGatewayAllowed(client.socket.conn.RemoteAddr(), gateway) {
  102. // assume PROXY connections are always secure
  103. if client.ApplyProxiedIP(params[2], true) {
  104. return nil
  105. } else {
  106. return errBadProxyLine
  107. }
  108. }
  109. }
  110. // real source IP is not authorized to issue PROXY:
  111. return errBadGatewayAddress
  112. }