Testing ground for GUI
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.

3462 lines
84KB

  1. //
  2. // Copyright (c) 2014 - 2018, Přemysl Eric Janouch <p@janouch.name>
  3. //
  4. // Permission to use, copy, modify, and/or distribute this software for any
  5. // purpose with or without fee is hereby granted.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. //
  15. // hid is a straight-forward port of kike IRCd from C.
  16. package main
  17. import (
  18. "bufio"
  19. "bytes"
  20. "crypto/sha256"
  21. "crypto/tls"
  22. "encoding/hex"
  23. "errors"
  24. "flag"
  25. "fmt"
  26. "io"
  27. "io/ioutil"
  28. "log/syslog"
  29. "net"
  30. "os"
  31. "os/signal"
  32. "os/user"
  33. "path/filepath"
  34. "regexp"
  35. "strconv"
  36. "strings"
  37. "syscall"
  38. "time"
  39. )
  40. var debugMode = false
  41. const (
  42. projectName = "hid"
  43. // TODO: Consider using the same version number for all subprojects.
  44. projectVersion = "0"
  45. )
  46. // --- Logging -----------------------------------------------------------------
  47. type logPrio int
  48. const (
  49. prioFatal logPrio = iota
  50. prioError
  51. prioWarning
  52. prioStatus
  53. prioDebug
  54. )
  55. func (lp logPrio) prefix() string {
  56. switch lp {
  57. case prioFatal:
  58. return "fatal: "
  59. case prioError:
  60. return "error: "
  61. case prioWarning:
  62. return "warning: "
  63. case prioStatus:
  64. return ""
  65. case prioDebug:
  66. return "debug: "
  67. default:
  68. panic("unhandled log priority")
  69. }
  70. }
  71. func (lp logPrio) syslogPrio() syslog.Priority {
  72. switch lp {
  73. case prioFatal:
  74. return syslog.LOG_ERR
  75. case prioError:
  76. return syslog.LOG_ERR
  77. case prioWarning:
  78. return syslog.LOG_WARNING
  79. case prioStatus:
  80. return syslog.LOG_INFO
  81. case prioDebug:
  82. return syslog.LOG_DEBUG
  83. default:
  84. panic("unhandled log priority")
  85. }
  86. }
  87. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  88. func logMessageStdio(prio logPrio, format string, args ...interface{}) {
  89. // TODO: isatty-enabled colors based on prio.
  90. os.Stderr.WriteString(time.Now().Format("2006-01-02 15:04:05 ") +
  91. prio.prefix() + fmt.Sprintf(format, args...) + "\n")
  92. }
  93. func logMessageSystemd(prio logPrio, format string, args ...interface{}) {
  94. if prio == prioFatal {
  95. // There is no corresponding syslog severity.
  96. format = "fatal: " + format
  97. }
  98. fmt.Fprintf(os.Stderr, "<%d>%s\n",
  99. prio.syslogPrio(), fmt.Sprintf(format, args...))
  100. }
  101. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  102. var logMessage = logMessageStdio
  103. func printDebug(format string, args ...interface{}) {
  104. if debugMode {
  105. logMessage(prioDebug, format, args...)
  106. }
  107. }
  108. func printStatus(format string, args ...interface{}) {
  109. logMessage(prioStatus, format, args...)
  110. }
  111. func printWarning(format string, args ...interface{}) {
  112. logMessage(prioWarning, format, args...)
  113. }
  114. func printError(format string, args ...interface{}) {
  115. logMessage(prioError, format, args...)
  116. }
  117. // "fatal" is reserved for failures that would harm further operation.
  118. func printFatal(format string, args ...interface{}) {
  119. logMessage(prioFatal, format, args...)
  120. }
  121. func exitFatal(format string, args ...interface{}) {
  122. printFatal(format, args...)
  123. os.Exit(1)
  124. }
  125. // --- Utilities ---------------------------------------------------------------
  126. // Split a string by a set of UTF-8 delimiters, optionally ignoring empty items.
  127. func splitString(s, delims string, ignoreEmpty bool) (result []string) {
  128. for {
  129. end := strings.IndexAny(s, delims)
  130. if end < 0 {
  131. break
  132. }
  133. if !ignoreEmpty || end != 0 {
  134. result = append(result, s[:end])
  135. }
  136. s = s[end+1:]
  137. }
  138. if !ignoreEmpty || s != "" {
  139. result = append(result, s)
  140. }
  141. return
  142. }
  143. //
  144. // Trivial SSL/TLS autodetection. The first block of data returned by Recvfrom
  145. // must be at least three octets long for this to work reliably, but that should
  146. // not pose a problem in practice. We might try waiting for them.
  147. //
  148. // SSL2: 1xxx xxxx | xxxx xxxx | <1>
  149. // (message length) (client hello)
  150. // SSL3/TLS: <22> | <3> | xxxx xxxx
  151. // (handshake)| (protocol version)
  152. //
  153. // Note that Go 1.12's crypto/tls offers a slightly more straight-forward
  154. // solution: "If a client sends an initial message that does not look like TLS,
  155. // the server will no longer reply with an alert, and it will expose the
  156. // underlying net.Conn in the new field Conn of RecordHeaderError."
  157. func detectTLS(sysconn syscall.RawConn) (isTLS bool) {
  158. sysconn.Read(func(fd uintptr) (done bool) {
  159. var buf [3]byte
  160. n, _, err := syscall.Recvfrom(int(fd), buf[:], syscall.MSG_PEEK)
  161. switch {
  162. case n == 3:
  163. isTLS = buf[0]&0x80 != 0 && buf[2] == 1
  164. fallthrough
  165. case n == 2:
  166. isTLS = isTLS || buf[0] == 22 && buf[1] == 3
  167. case n == 1:
  168. isTLS = buf[0] == 22
  169. case err == syscall.EAGAIN:
  170. return false
  171. }
  172. return true
  173. })
  174. return isTLS
  175. }
  176. // --- File system -------------------------------------------------------------
  177. // Look up the value of an XDG path from environment, or fall back to a default.
  178. func getXDGHomeDir(name, def string) string {
  179. env := os.Getenv(name)
  180. if env != "" && env[0] == filepath.Separator {
  181. return env
  182. }
  183. home := ""
  184. if v, ok := os.LookupEnv("HOME"); ok {
  185. home = v
  186. } else if u, _ := user.Current(); u != nil {
  187. home = u.HomeDir
  188. }
  189. return filepath.Join(home, def)
  190. }
  191. func resolveRelativeFilenameGeneric(paths []string, filename string) string {
  192. for _, path := range paths {
  193. // As per XDG spec, relative paths are ignored.
  194. if path == "" || path[0] != filepath.Separator {
  195. continue
  196. }
  197. file := filepath.Join(path, filename)
  198. if _, err := os.Stat(file); err == nil {
  199. return file
  200. }
  201. }
  202. return ""
  203. }
  204. // Retrieve all XDG base directories for configuration files.
  205. func getXDGConfigDirs() (result []string) {
  206. home := getXDGHomeDir("XDG_CONFIG_HOME", ".config")
  207. if home != "" {
  208. result = append(result, home)
  209. }
  210. dirs := os.Getenv("XDG_CONFIG_DIRS")
  211. if dirs == "" {
  212. dirs = "/etc/xdg"
  213. }
  214. for _, path := range strings.Split(dirs, ":") {
  215. if path != "" {
  216. result = append(result, path)
  217. }
  218. }
  219. return
  220. }
  221. func resolveRelativeConfigFilename(filename string) string {
  222. return resolveRelativeFilenameGeneric(getXDGConfigDirs(),
  223. filepath.Join(projectName, filename))
  224. }
  225. func findTildeHome(username string) string {
  226. if username != "" {
  227. if u, _ := user.Lookup(username); u != nil {
  228. return u.HomeDir
  229. }
  230. } else if u, _ := user.Current(); u != nil {
  231. return u.HomeDir
  232. } else if v, ok := os.LookupEnv("HOME"); ok {
  233. return v
  234. }
  235. printDebug("failed to expand the home directory for %s", username)
  236. return "~" + username
  237. }
  238. func resolveFilename(filename string, relativeCB func(string) string) string {
  239. // Absolute path is absolute.
  240. if filename == "" || filename[0] == filepath.Separator {
  241. return filename
  242. }
  243. if filename[0] != '~' {
  244. return relativeCB(filename)
  245. }
  246. // Paths to home directories ought to be absolute.
  247. var n int
  248. for n = 0; n < len(filename); n++ {
  249. if filename[n] == filepath.Separator {
  250. break
  251. }
  252. }
  253. return findTildeHome(filename[1:n]) + filename[n:]
  254. }
  255. // --- Simple file I/O ---------------------------------------------------------
  256. // Overwrites filename contents with data; creates directories as needed.
  257. func writeFile(path string, data []byte) error {
  258. if dir := filepath.Dir(path); dir != "." {
  259. if err := os.MkdirAll(dir, 0755); err != nil {
  260. return err
  261. }
  262. }
  263. return ioutil.WriteFile(path, data, 0644)
  264. }
  265. // Wrapper for writeFile that makes sure that the new data has been written
  266. // to disk in its entirety before overriding the old file.
  267. func writeFileSafe(path string, data []byte) error {
  268. temp := path + ".new"
  269. if err := writeFile(temp, data); err != nil {
  270. return err
  271. }
  272. return os.Rename(temp, path)
  273. }
  274. // --- Simple configuration ----------------------------------------------------
  275. // This is the bare minimum to make an application configurable.
  276. // Keys are stripped of surrounding whitespace, values are not.
  277. type simpleConfigItem struct {
  278. key string // INI key
  279. def string // default value
  280. description string // documentation
  281. }
  282. type simpleConfig map[string]string
  283. func (sc simpleConfig) loadDefaults(table []simpleConfigItem) {
  284. for _, item := range table {
  285. sc[item.key] = item.def
  286. }
  287. }
  288. func (sc simpleConfig) updateFromFile() error {
  289. basename := projectName + ".conf"
  290. path := resolveFilename(basename, resolveRelativeConfigFilename)
  291. if path == "" {
  292. return &os.PathError{
  293. Op: "cannot find",
  294. Path: basename,
  295. Err: os.ErrNotExist,
  296. }
  297. }
  298. f, err := os.Open(path)
  299. if err != nil {
  300. return err
  301. }
  302. defer f.Close()
  303. scanner := bufio.NewScanner(f)
  304. for lineNo := 1; scanner.Scan(); lineNo++ {
  305. line := strings.TrimLeft(scanner.Text(), " \t")
  306. if line == "" || strings.HasPrefix(line, "#") {
  307. continue
  308. }
  309. equals := strings.IndexByte(line, '=')
  310. if equals <= 0 {
  311. return fmt.Errorf("%s:%d: malformed line", path, lineNo)
  312. }
  313. sc[strings.TrimRight(line[:equals], " \t")] = line[equals+1:]
  314. }
  315. return scanner.Err()
  316. }
  317. func writeConfigurationFile(pathHint string, data []byte) (string, error) {
  318. path := pathHint
  319. if path == "" {
  320. path = filepath.Join(getXDGHomeDir("XDG_CONFIG_HOME", ".config"),
  321. projectName, projectName+".conf")
  322. }
  323. if err := writeFileSafe(path, data); err != nil {
  324. return "", err
  325. }
  326. return path, nil
  327. }
  328. func simpleConfigWriteDefault(pathHint string, prolog string,
  329. table []simpleConfigItem) (string, error) {
  330. data := []byte(prolog)
  331. for _, item := range table {
  332. data = append(data, fmt.Sprintf("# %s\n%s=%s\n",
  333. item.description, item.key, item.def)...)
  334. }
  335. return writeConfigurationFile(pathHint, data)
  336. }
  337. /// Convenience wrapper suitable for most simple applications.
  338. func callSimpleConfigWriteDefault(pathHint string, table []simpleConfigItem) {
  339. prologLines := []string{
  340. `# ` + projectName + ` ` + projectVersion + ` configuration file`,
  341. "#",
  342. `# Relative paths are searched for in ${XDG_CONFIG_HOME:-~/.config}`,
  343. `# /` + projectName + ` as well as in $XDG_CONFIG_DIRS/` + projectName,
  344. ``,
  345. ``,
  346. }
  347. path, err := simpleConfigWriteDefault(
  348. pathHint, strings.Join(prologLines, "\n"), table)
  349. if err != nil {
  350. exitFatal("%s", err)
  351. }
  352. printStatus("configuration written to `%s'", path)
  353. }
  354. // --- Configuration -----------------------------------------------------------
  355. var configTable = []simpleConfigItem{
  356. {"server_name", "", "Server name"},
  357. {"server_info", "My server", "Brief server description"},
  358. {"motd", "", "MOTD filename"},
  359. {"catalog", "", "Localisation catalog"},
  360. {"bind", ":6667", "Bind addresses of the IRC server"},
  361. {"tls_cert", "", "Server TLS certificate (PEM)"},
  362. {"tls_key", "", "Server TLS private key (PEM)"},
  363. {"operators", "", "IRCop TLS certificate SHA-256 fingerprints"},
  364. {"max_connections", "0", "Global connection limit"},
  365. {"ping_interval", "180", "Interval between PINGs (sec)"},
  366. }
  367. // --- Rate limiter ------------------------------------------------------------
  368. type floodDetector struct {
  369. interval time.Duration // interval for the limit in seconds
  370. limit uint // maximum number of events allowed
  371. timestamps []time.Time // timestamps of last events
  372. pos uint // index of the oldest event
  373. }
  374. func newFloodDetector(interval time.Duration, limit uint) *floodDetector {
  375. return &floodDetector{
  376. interval: interval,
  377. limit: limit,
  378. timestamps: make([]time.Time, limit+1),
  379. pos: 0,
  380. }
  381. }
  382. func (fd *floodDetector) check() bool {
  383. now := time.Now()
  384. fd.timestamps[fd.pos] = now
  385. fd.pos++
  386. if fd.pos > fd.limit {
  387. fd.pos = 0
  388. }
  389. var count uint
  390. begin := now.Add(-fd.interval)
  391. for _, ts := range fd.timestamps {
  392. if ts.After(begin) {
  393. count++
  394. }
  395. }
  396. return count <= fd.limit
  397. }
  398. // --- IRC protocol ------------------------------------------------------------
  399. //go:generate sh -c "./hid-gen-replies.sh > hid-replies.go < hid-replies"
  400. func ircToLower(c byte) byte {
  401. switch c {
  402. case '[':
  403. return '{'
  404. case ']':
  405. return '}'
  406. case '\\':
  407. return '|'
  408. case '~':
  409. return '^'
  410. }
  411. if c >= 'A' && c <= 'Z' {
  412. return c + ('a' - 'A')
  413. }
  414. return c
  415. }
  416. func ircToUpper(c byte) byte {
  417. switch c {
  418. case '{':
  419. return '['
  420. case '}':
  421. return ']'
  422. case '|':
  423. return '\\'
  424. case '^':
  425. return '~'
  426. }
  427. if c >= 'a' && c <= 'z' {
  428. return c - ('a' - 'A')
  429. }
  430. return c
  431. }
  432. // Convert identifier to a canonical form for case-insensitive comparisons.
  433. // ircToUpper is used so that statically initialized maps can be in uppercase.
  434. func ircToCanon(ident string) string {
  435. var canon []byte
  436. for _, c := range []byte(ident) {
  437. canon = append(canon, ircToUpper(c))
  438. }
  439. return string(canon)
  440. }
  441. func ircEqual(s1, s2 string) bool {
  442. return ircToCanon(s1) == ircToCanon(s2)
  443. }
  444. func ircFnmatch(pattern string, s string) bool {
  445. pattern, s = ircToCanon(pattern), ircToCanon(s)
  446. // FIXME: This should not support [] ranges and handle '/' specially.
  447. // We could translate the pattern to a regular expression.
  448. matched, _ := filepath.Match(pattern, s)
  449. return matched
  450. }
  451. var reMsg = regexp.MustCompile(
  452. `^(?:@([^ ]*) +)?(?::([^! ]*)(?:!([^@]*)@([^ ]*))? +)?([^ ]+)(.*)?$`)
  453. var reArgs = regexp.MustCompile(`:.*| [^: ][^ ]*`)
  454. type message struct {
  455. tags map[string]string // IRC 3.2 message tags
  456. nick string // optional nickname
  457. user string // optional username
  458. host string // optional hostname or IP address
  459. command string // command name
  460. params []string // arguments
  461. }
  462. func ircUnescapeMessageTag(value string) string {
  463. var buf []byte
  464. escape := false
  465. for i := 0; i < len(value); i++ {
  466. if escape {
  467. switch value[i] {
  468. case ':':
  469. buf = append(buf, ';')
  470. case 's':
  471. buf = append(buf, ' ')
  472. case 'r':
  473. buf = append(buf, '\r')
  474. case 'n':
  475. buf = append(buf, '\n')
  476. default:
  477. buf = append(buf, value[i])
  478. }
  479. escape = false
  480. } else if value[i] == '\\' {
  481. escape = true
  482. } else {
  483. buf = append(buf, value[i])
  484. }
  485. }
  486. return string(buf)
  487. }
  488. func ircParseMessageTags(tags string, out map[string]string) {
  489. for _, tag := range splitString(tags, ";", true /* ignoreEmpty */) {
  490. if equal := strings.IndexByte(tag, '='); equal < 0 {
  491. out[tag] = ""
  492. } else {
  493. out[tag[:equal]] = ircUnescapeMessageTag(tag[equal+1:])
  494. }
  495. }
  496. }
  497. func ircParseMessage(line string) *message {
  498. m := reMsg.FindStringSubmatch(line)
  499. if m == nil {
  500. return nil
  501. }
  502. msg := message{nil, m[2], m[3], m[4], m[5], nil}
  503. if m[1] != "" {
  504. msg.tags = make(map[string]string)
  505. ircParseMessageTags(m[1], msg.tags)
  506. }
  507. for _, x := range reArgs.FindAllString(m[6], -1) {
  508. msg.params = append(msg.params, x[1:])
  509. }
  510. return &msg
  511. }
  512. // --- IRC token validation ----------------------------------------------------
  513. // Everything as per RFC 2812
  514. const (
  515. ircMaxNickname = 9
  516. ircMaxHostname = 63
  517. ircMaxChannelName = 50
  518. ircMaxMessageLength = 510
  519. )
  520. const (
  521. reClassSpecial = "\\[\\]\\\\`_^{|}"
  522. // "shortname" from RFC 2812 doesn't work how its author thought it would.
  523. reShortname = "[0-9A-Za-z](-*[0-9A-Za-z])*"
  524. )
  525. var (
  526. reHostname = regexp.MustCompile(
  527. `^` + reShortname + `(\.` + reShortname + `)*$`)
  528. // Extending ASCII to the whole range of Unicode letters.
  529. reNickname = regexp.MustCompile(
  530. `^[\pL` + reClassSpecial + `][\pL` + reClassSpecial + `0-9-]*$`)
  531. // Notably, this won't match invalid UTF-8 characters, although the
  532. // behaviour seems to be unstated in the documentation.
  533. reUsername = regexp.MustCompile(`^[^\0\r\n @]+$`)
  534. reChannelName = regexp.MustCompile(`^[^\0\007\r\n ,:]+$`)
  535. reKey = regexp.MustCompile(`^[^\r\n\f\t\v ]{1,23}$`)
  536. reUserMask = regexp.MustCompile(`^[^!@]+![^!@]+@[^@!]+$`)
  537. reFingerprint = regexp.MustCompile(`^[a-fA-F0-9]{64}$`)
  538. )
  539. func ircValidateHostname(hostname string) error {
  540. if hostname == "" {
  541. return errors.New("the value is empty")
  542. }
  543. if !reHostname.MatchString(hostname) {
  544. return errors.New("invalid format")
  545. }
  546. if len(hostname) > ircMaxHostname {
  547. return errors.New("the value is too long")
  548. }
  549. return nil
  550. }
  551. func ircIsValidNickname(nickname string) bool {
  552. return len(nickname) <= ircMaxNickname && reNickname.MatchString(nickname)
  553. }
  554. func ircIsValidUsername(username string) bool {
  555. // XXX: We really should put a limit on this
  556. // despite the RFC not mentioning one.
  557. return reUsername.MatchString(username)
  558. }
  559. func ircIsValidChannelName(name string) bool {
  560. return len(name) <= ircMaxChannelName && reChannelName.MatchString(name)
  561. }
  562. func ircIsValidKey(key string) bool {
  563. // XXX: Should be 7-bit as well but whatever.
  564. return reKey.MatchString(key)
  565. }
  566. func ircIsValidUserMask(mask string) bool {
  567. return reUserMask.MatchString(mask)
  568. }
  569. func ircIsValidFingerprint(fp string) bool {
  570. return reFingerprint.MatchString(fp)
  571. }
  572. // --- Clients (equals users) --------------------------------------------------
  573. type connCloseWriter interface {
  574. net.Conn
  575. CloseWrite() error
  576. }
  577. const ircSupportedUserModes = "aiwros"
  578. const (
  579. ircUserModeInvisible uint = 1 << iota
  580. ircUserModeRxWallops
  581. ircUserModeRestricted
  582. ircUserModeOperator
  583. ircUserModeRxServerNotices
  584. )
  585. const (
  586. ircCapMultiPrefix uint = 1 << iota
  587. ircCapInviteNotify
  588. ircCapEchoMessage
  589. ircCapUserhostInNames
  590. ircCapServerTime
  591. )
  592. type client struct {
  593. transport net.Conn // underlying connection
  594. tls *tls.Conn // TLS, if detected
  595. conn connCloseWriter // high-level connection
  596. recvQ []byte // unprocessed input
  597. sendQ []byte // unprocessed output
  598. reading bool // whether a reading goroutine is running
  599. writing bool // whether a writing goroutine is running
  600. closing bool // whether we're closing the connection
  601. killTimer *time.Timer // hard kill timeout
  602. opened time.Time // when the connection was opened
  603. nSentMessages uint // number of sent messages total
  604. sentBytes int // number of sent bytes total
  605. nReceivedMessages uint // number of received messages total
  606. receivedBytes int // number of received bytes total
  607. hostname string // hostname or IP shown to the network
  608. port string // port of the peer as a string
  609. address string // full network address
  610. pingTimer *time.Timer // we should send a PING
  611. timeoutTimer *time.Timer // connection seems to be dead
  612. registered bool // the user has registered
  613. capNegotiating bool // negotiating capabilities
  614. capsEnabled uint // enabled capabilities
  615. capVersion uint // CAP protocol version
  616. tlsCertFingerprint string // client certificate fingerprint
  617. nickname string // IRC nickname (main identifier)
  618. username string // IRC username
  619. realname string // IRC realname (or e-mail)
  620. mode uint // user's mode
  621. awayMessage string // away message
  622. lastActive time.Time // last PRIVMSG, to get idle time
  623. invites map[string]bool // channel invitations by operators
  624. antiflood *floodDetector // flood detector
  625. }
  626. // --- Channels ----------------------------------------------------------------
  627. const ircSupportedChanModes = "ov" + "beI" + "imnqpst" + "kl"
  628. const (
  629. ircChanModeInviteOnly uint = 1 << iota
  630. ircChanModeModerated
  631. ircChanModeNoOutsideMsgs
  632. ircChanModeQuiet
  633. ircChanModePrivate
  634. ircChanModeSecret
  635. ircChanModeProtectedTopic
  636. ircChanModeOperator
  637. ircChanModeVoice
  638. )
  639. type channel struct {
  640. name string // channel name
  641. modes uint // channel modes
  642. key string // channel key
  643. userLimit int // user limit or -1
  644. created time.Time // creation time
  645. topic string // channel topic
  646. topicWho string // who set the topic
  647. topicTime time.Time // when the topic was set
  648. userModes map[*client]uint // modes for all channel users
  649. banList []string // ban list
  650. exceptionList []string // exceptions from bans
  651. inviteList []string // exceptions from +I
  652. }
  653. func (ch *channel) getMode(discloseSecrets bool) string {
  654. var buf []byte
  655. if 0 != ch.modes&ircChanModeInviteOnly {
  656. buf = append(buf, 'i')
  657. }
  658. if 0 != ch.modes&ircChanModeModerated {
  659. buf = append(buf, 'm')
  660. }
  661. if 0 != ch.modes&ircChanModeNoOutsideMsgs {
  662. buf = append(buf, 'n')
  663. }
  664. if 0 != ch.modes&ircChanModeQuiet {
  665. buf = append(buf, 'q')
  666. }
  667. if 0 != ch.modes&ircChanModePrivate {
  668. buf = append(buf, 'p')
  669. }
  670. if 0 != ch.modes&ircChanModeSecret {
  671. buf = append(buf, 's')
  672. }
  673. if 0 != ch.modes&ircChanModeProtectedTopic {
  674. buf = append(buf, 'r')
  675. }
  676. if ch.userLimit != -1 {
  677. buf = append(buf, 'l')
  678. }
  679. if ch.key != "" {
  680. buf = append(buf, 'k')
  681. }
  682. // XXX: Is it correct to split it? Try it on an existing implementation.
  683. if discloseSecrets {
  684. if ch.userLimit != -1 {
  685. buf = append(buf, fmt.Sprintf(" %d", ch.userLimit)...)
  686. }
  687. if ch.key != "" {
  688. buf = append(buf, fmt.Sprintf(" %s", ch.key)...)
  689. }
  690. }
  691. return string(buf)
  692. }
  693. // --- IRC server context ------------------------------------------------------
  694. type whowasInfo struct {
  695. nickname, username, realname, hostname string
  696. }
  697. func newWhowasInfo(c *client) *whowasInfo {
  698. return &whowasInfo{
  699. nickname: c.nickname,
  700. username: c.username,
  701. realname: c.realname,
  702. hostname: c.hostname,
  703. }
  704. }
  705. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  706. type ircCommand struct {
  707. requiresRegistration bool
  708. handler func(*message, *client)
  709. nReceived uint // number of commands received
  710. bytesReceived int // number of bytes received total
  711. }
  712. type preparedEvent struct {
  713. client *client
  714. host string // client's hostname or literal IP address
  715. isTLS bool // the client seems to use TLS
  716. }
  717. type readEvent struct {
  718. client *client
  719. data []byte // new data from the client
  720. err error // read error
  721. }
  722. type writeEvent struct {
  723. client *client
  724. written int // amount of bytes written
  725. err error // write error
  726. }
  727. // TODO: Maybe we want to keep it in a struct?
  728. // A better question might be: can we run multiple instances of it?
  729. var (
  730. // network
  731. listeners []net.Listener
  732. clients = make(map[*client]bool)
  733. // IRC state
  734. // XXX: Beware that maps with identifier keys need to be indexed correctly.
  735. // We might want to enforce accessor functions for users and channels.
  736. started time.Time // when the server has been started
  737. users = make(map[string]*client) // maps nicknames to clients
  738. channels = make(map[string]*channel) // maps channel names to data
  739. whowas = make(map[string]*whowasInfo) // WHOWAS registry
  740. // event loop
  741. quitting bool
  742. quitTimer <-chan time.Time
  743. sigs = make(chan os.Signal, 1)
  744. conns = make(chan net.Conn)
  745. prepared = make(chan preparedEvent)
  746. reads = make(chan readEvent)
  747. writes = make(chan writeEvent)
  748. timers = make(chan func())
  749. // configuration
  750. config simpleConfig // server configuration
  751. tlsConf *tls.Config // TLS connection configuration
  752. serverName string // our server name
  753. pingInterval time.Duration // ping interval
  754. maxConnections int // max connections allowed or 0
  755. motd []string // MOTD (none if empty)
  756. catalog map[int]string // message catalog for server msgs
  757. operators map[string]bool // TLS certificate fingerprints for IRCops
  758. )
  759. // Forcefully tear down all connections.
  760. func forceQuit(reason string) {
  761. if !quitting {
  762. exitFatal("forceQuit called without initiateQuit")
  763. }
  764. printStatus("forced shutdown (%s)", reason)
  765. for c := range clients {
  766. // initiateQuit has already unregistered the client.
  767. c.kill("Shutting down")
  768. }
  769. }
  770. // Initiate a clean shutdown of the whole daemon.
  771. func initiateQuit() {
  772. printStatus("shutting down")
  773. for _, ln := range listeners {
  774. if err := ln.Close(); err != nil {
  775. printError("%s", err)
  776. }
  777. }
  778. for c := range clients {
  779. c.closeLink("Shutting down")
  780. }
  781. quitTimer = time.After(5 * time.Second)
  782. quitting = true
  783. }
  784. func ircChannelCreate(name string) *channel {
  785. ch := &channel{
  786. name: name,
  787. userLimit: -1,
  788. created: time.Now(),
  789. userModes: make(map[*client]uint),
  790. }
  791. channels[ircToCanon(name)] = ch
  792. return ch
  793. }
  794. func ircChannelDestroyIfEmpty(ch *channel) {
  795. if len(ch.userModes) == 0 {
  796. delete(channels, ircToCanon(ch.name))
  797. }
  798. }
  799. func ircNotifyRoommates(c *client, message string) {
  800. targets := make(map[*client]bool)
  801. for _, ch := range channels {
  802. _, present := ch.userModes[c]
  803. if !present || 0 != ch.modes&ircChanModeQuiet {
  804. continue
  805. }
  806. for client := range ch.userModes {
  807. targets[client] = true
  808. }
  809. }
  810. for roommate := range targets {
  811. if roommate != c {
  812. roommate.send(message)
  813. }
  814. }
  815. }
  816. // --- Clients (continued) -----------------------------------------------------
  817. func (c *client) printDebug(format string, args ...interface{}) {
  818. if debugMode {
  819. printDebug("(%s) %s", c.address, fmt.Sprintf(format, args...))
  820. }
  821. }
  822. func ircAppendClientModes(m uint, mode []byte) []byte {
  823. if 0 != m&ircUserModeInvisible {
  824. mode = append(mode, 'i')
  825. }
  826. if 0 != m&ircUserModeRxWallops {
  827. mode = append(mode, 'w')
  828. }
  829. if 0 != m&ircUserModeRestricted {
  830. mode = append(mode, 'r')
  831. }
  832. if 0 != m&ircUserModeOperator {
  833. mode = append(mode, 'o')
  834. }
  835. if 0 != m&ircUserModeRxServerNotices {
  836. mode = append(mode, 's')
  837. }
  838. return mode
  839. }
  840. func (c *client) getMode() string {
  841. var mode []byte
  842. if c.awayMessage != "" {
  843. mode = append(mode, 'a')
  844. }
  845. return string(ircAppendClientModes(c.mode, mode))
  846. }
  847. func (c *client) send(line string) {
  848. if c.conn == nil || c.closing {
  849. return
  850. }
  851. oldSendQLen := len(c.sendQ)
  852. // So far there's only one message tag we use, so we can do it simple;
  853. // note that a 1024-character limit applies to messages with tags on.
  854. if 0 != c.capsEnabled&ircCapServerTime {
  855. c.sendQ = time.Now().UTC().
  856. AppendFormat(c.sendQ, "@time=2006-01-02T15:04:05.000Z ")
  857. }
  858. bytes := []byte(line)
  859. if len(bytes) > ircMaxMessageLength {
  860. bytes = bytes[:ircMaxMessageLength]
  861. }
  862. c.printDebug("<- %s", bytes)
  863. // TODO: Kill the connection above some "SendQ" threshold (careful!)
  864. c.sendQ = append(c.sendQ, bytes...)
  865. c.sendQ = append(c.sendQ, "\r\n"...)
  866. c.flushSendQ()
  867. // Technically we haven't sent it yet but that's a minor detail
  868. c.nSentMessages++
  869. c.sentBytes += len(c.sendQ) - oldSendQLen
  870. }
  871. func (c *client) sendf(format string, a ...interface{}) {
  872. c.send(fmt.Sprintf(format, a...))
  873. }
  874. func (c *client) addToWhowas() {
  875. // Only keeping one entry for each nickname.
  876. // TODO: Make sure this list doesn't get too long, for example by
  877. // putting them in a linked list ordered by time.
  878. whowas[ircToCanon(c.nickname)] = newWhowasInfo(c)
  879. }
  880. func (c *client) nicknameOrStar() string {
  881. if c.nickname == "" {
  882. return "*"
  883. }
  884. return c.nickname
  885. }
  886. func (c *client) unregister(reason string) {
  887. if !c.registered {
  888. return
  889. }
  890. ircNotifyRoommates(c, fmt.Sprintf(":%s!%s@%s QUIT :%s",
  891. c.nickname, c.username, c.hostname, reason))
  892. // The QUIT message will take care of state on clients.
  893. for _, ch := range channels {
  894. delete(ch.userModes, c)
  895. ircChannelDestroyIfEmpty(ch)
  896. }
  897. c.addToWhowas()
  898. delete(users, ircToCanon(c.nickname))
  899. c.nickname = ""
  900. c.registered = false
  901. }
  902. // Close the connection and forget about the client.
  903. func (c *client) kill(reason string) {
  904. if reason == "" {
  905. c.unregister("Client exited")
  906. } else {
  907. c.unregister(reason)
  908. }
  909. c.printDebug("client destroyed (%s)", reason)
  910. // Try to send a "close notify" alert if the TLS object is ready,
  911. // otherwise just tear down the transport.
  912. if c.conn != nil {
  913. _ = c.conn.Close()
  914. } else {
  915. _ = c.transport.Close()
  916. }
  917. c.cancelTimers()
  918. delete(clients, c)
  919. }
  920. // Tear down the client connection, trying to do so in a graceful manner.
  921. func (c *client) closeLink(reason string) {
  922. // Let's just cut the connection, the client can try again later.
  923. // We also want to avoid accidentally writing to the socket before
  924. // address resolution has finished.
  925. if c.conn == nil {
  926. c.kill(reason)
  927. return
  928. }
  929. if c.closing {
  930. return
  931. }
  932. // We push an "ERROR" message to the write buffer and let the writer send
  933. // it, with some arbitrary timeout. The "closing" state makes sure
  934. // that a/ we ignore any successive messages, and b/ that the connection
  935. // is killed after the write buffer is transferred and emptied.
  936. // (Since we send this message, we don't need to call CloseWrite here.)
  937. c.sendf("ERROR :Closing link: %s[%s] (%s)",
  938. c.nicknameOrStar(), c.hostname /* TODO host IP? */, reason)
  939. c.closing = true
  940. c.unregister(reason)
  941. c.setKillTimer()
  942. }
  943. func (c *client) inMaskList(masks []string) bool {
  944. client := fmt.Sprintf("%s!%s@%s", c.nickname, c.username, c.hostname)
  945. for _, mask := range masks {
  946. if ircFnmatch(mask, client) {
  947. return true
  948. }
  949. }
  950. return false
  951. }
  952. func (c *client) getTLSCertFingerprint() string {
  953. if c.tls == nil {
  954. return ""
  955. }
  956. peerCerts := c.tls.ConnectionState().PeerCertificates
  957. if len(peerCerts) == 0 {
  958. return ""
  959. }
  960. hash := sha256.Sum256(peerCerts[0].Raw)
  961. return hex.EncodeToString(hash[:])
  962. }
  963. // --- Timers ------------------------------------------------------------------
  964. // Free the resources of timers that haven't fired yet and for timers that are
  965. // in between firing and being collected by the event loop, mark that the event
  966. // should not be acted upon.
  967. func (c *client) cancelTimers() {
  968. for _, timer := range []**time.Timer{
  969. &c.killTimer, &c.timeoutTimer, &c.pingTimer,
  970. } {
  971. if *timer != nil {
  972. (*timer).Stop()
  973. *timer = nil
  974. }
  975. }
  976. }
  977. // Arrange for a function to be called later from the main goroutine.
  978. func (c *client) setTimer(timer **time.Timer, delay time.Duration, cb func()) {
  979. c.cancelTimers()
  980. var identityCapture *time.Timer
  981. identityCapture = time.AfterFunc(delay, func() {
  982. timers <- func() {
  983. // The timer might have been cancelled or even replaced.
  984. // When the client is killed, this will be nil.
  985. if *timer == identityCapture {
  986. cb()
  987. }
  988. }
  989. })
  990. *timer = identityCapture
  991. }
  992. func (c *client) setKillTimer() {
  993. c.setTimer(&c.killTimer, pingInterval, func() {
  994. c.kill("Timeout")
  995. })
  996. }
  997. func (c *client) setTimeoutTimer() {
  998. c.setTimer(&c.timeoutTimer, pingInterval, func() {
  999. c.closeLink(fmt.Sprintf("Ping timeout: >%d seconds",
  1000. pingInterval/time.Second))
  1001. })
  1002. }
  1003. func (c *client) setPingTimer() {
  1004. c.setTimer(&c.pingTimer, pingInterval, func() {
  1005. c.sendf("PING :%s", serverName)
  1006. c.setTimeoutTimer()
  1007. })
  1008. }
  1009. // --- IRC command handling ----------------------------------------------------
  1010. func (c *client) makeReply(id int, ap ...interface{}) string {
  1011. s := fmt.Sprintf(":%s %03d %s ", serverName, id, c.nicknameOrStar())
  1012. if reply, ok := catalog[id]; ok {
  1013. return s + fmt.Sprintf(reply, ap...)
  1014. }
  1015. return s + fmt.Sprintf(defaultReplies[id], ap...)
  1016. }
  1017. // XXX: This way simple static analysis cannot typecheck the arguments, so we
  1018. // need to be careful.
  1019. func (c *client) sendReply(id int, args ...interface{}) {
  1020. c.send(c.makeReply(id, args...))
  1021. }
  1022. /// Send a space-separated list of words across as many replies as needed.
  1023. func (c *client) sendReplyVector(id int, items []string, args ...interface{}) {
  1024. common := c.makeReply(id, args...)
  1025. // We always send at least one message (there might be a client that
  1026. // expects us to send this message at least once).
  1027. if len(items) == 0 {
  1028. items = append(items, "")
  1029. }
  1030. for len(items) > 0 {
  1031. // If not even a single item fits in the limit (which may happen,
  1032. // in theory) it just gets cropped. We could also skip it.
  1033. reply := append([]byte(common), items[0]...)
  1034. items = items[1:]
  1035. // Append as many items as fits in a single message.
  1036. for len(items) > 0 &&
  1037. len(reply)+1+len(items[0]) <= ircMaxMessageLength {
  1038. reply = append(reply, ' ')
  1039. reply = append(reply, items[0]...)
  1040. items = items[1:]
  1041. }
  1042. c.send(string(reply))
  1043. }
  1044. }
  1045. func (c *client) sendMOTD() {
  1046. if len(motd) == 0 {
  1047. c.sendReply(ERR_NOMOTD)
  1048. return
  1049. }
  1050. c.sendReply(RPL_MOTDSTART, serverName)
  1051. for _, line := range motd {
  1052. c.sendReply(RPL_MOTD, line)
  1053. }
  1054. c.sendReply(RPL_ENDOFMOTD)
  1055. }
  1056. func (c *client) sendLUSERS() {
  1057. nUsers, nServices, nOpers, nUnknown := 0, 0, 0, 0
  1058. for c := range clients {
  1059. if c.registered {
  1060. nUsers++
  1061. } else {
  1062. nUnknown++
  1063. }
  1064. if 0 != c.mode&ircUserModeOperator {
  1065. nOpers++
  1066. }
  1067. }
  1068. nChannels := 0
  1069. for _, ch := range channels {
  1070. if 0 != ch.modes&ircChanModeSecret {
  1071. nChannels++
  1072. }
  1073. }
  1074. c.sendReply(RPL_LUSERCLIENT, nUsers, nServices, 1 /* servers total */)
  1075. if nOpers != 0 {
  1076. c.sendReply(RPL_LUSEROP, nOpers)
  1077. }
  1078. if nUnknown != 0 {
  1079. c.sendReply(RPL_LUSERUNKNOWN, nUnknown)
  1080. }
  1081. if nChannels != 0 {
  1082. c.sendReply(RPL_LUSERCHANNELS, nChannels)
  1083. }
  1084. c.sendReply(RPL_LUSERME, nUsers+nServices+nUnknown, 0 /* peer servers */)
  1085. }
  1086. func ircIsThisMe(target string) bool {
  1087. // Target servers can also be matched by their users
  1088. if ircFnmatch(target, serverName) {
  1089. return true
  1090. }
  1091. _, ok := users[ircToCanon(target)]
  1092. return ok
  1093. }
  1094. func (c *client) sendISUPPORT() {
  1095. // Only # channels, +e supported, +I supported, unlimited arguments to MODE.
  1096. c.sendReply(RPL_ISUPPORT, fmt.Sprintf("CHANTYPES=# EXCEPTS INVEX MODES"+
  1097. " TARGMAX=WHOIS:,LIST:,NAMES:,PRIVMSG:1,NOTICE:1,KICK:"+
  1098. " NICKLEN=%d CHANNELLEN=%d", ircMaxNickname, ircMaxChannelName))
  1099. }
  1100. func (c *client) tryFinishRegistration() {
  1101. if c.registered || c.capNegotiating {
  1102. return
  1103. }
  1104. if c.nickname == "" || c.username == "" {
  1105. return
  1106. }
  1107. c.registered = true
  1108. c.sendReply(RPL_WELCOME, c.nickname, c.username, c.hostname)
  1109. c.sendReply(RPL_YOURHOST, serverName, projectVersion)
  1110. // The purpose of this message eludes me.
  1111. c.sendReply(RPL_CREATED, started.Format("Mon, 02 Jan 2006"))
  1112. c.sendReply(RPL_MYINFO, serverName, projectVersion,
  1113. ircSupportedUserModes, ircSupportedChanModes)
  1114. c.sendISUPPORT()
  1115. c.sendLUSERS()
  1116. c.sendMOTD()
  1117. if mode := c.getMode(); mode != "" {
  1118. c.sendf(":%s MODE %s :+%s", c.nickname, c.nickname, mode)
  1119. }
  1120. c.tlsCertFingerprint = c.getTLSCertFingerprint()
  1121. if c.tlsCertFingerprint != "" {
  1122. c.sendf(":%s NOTICE %s :Your TLS client certificate fingerprint is %s",
  1123. serverName, c.nickname, c.tlsCertFingerprint)
  1124. }
  1125. delete(whowas, ircToCanon(c.nickname))
  1126. }
  1127. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1128. // IRCv3 capability negotiation. See http://ircv3.org for details.
  1129. type ircCapArgs struct {
  1130. subcommand string // the subcommand being processed
  1131. fullParams string // whole parameter string
  1132. params []string // split parameters
  1133. target string // target parameter for replies
  1134. }
  1135. var ircCapTable = []struct {
  1136. flag uint // flag
  1137. name string // name of the capability
  1138. }{
  1139. {ircCapMultiPrefix, "multi-prefix"},
  1140. {ircCapInviteNotify, "invite-notify"},
  1141. {ircCapEchoMessage, "echo-message"},
  1142. {ircCapUserhostInNames, "userhost-in-names"},
  1143. {ircCapServerTime, "server-time"},
  1144. }
  1145. func (c *client) handleCAPLS(a *ircCapArgs) {
  1146. if len(a.params) == 1 {
  1147. if ver, err := strconv.ParseUint(a.params[0], 10, 32); err != nil {
  1148. c.sendReply(ERR_INVALIDCAPCMD, a.subcommand,
  1149. "Ignoring invalid protocol version number")
  1150. } else {
  1151. c.capVersion = uint(ver)
  1152. }
  1153. }
  1154. c.capNegotiating = true
  1155. c.sendf(":%s CAP %s LS :multi-prefix invite-notify echo-message"+
  1156. " userhost-in-names server-time", serverName, a.target)
  1157. }
  1158. func (c *client) handleCAPLIST(a *ircCapArgs) {
  1159. caps := []string{}
  1160. for _, cap := range ircCapTable {
  1161. if 0 != c.capsEnabled&cap.flag {
  1162. caps = append(caps, cap.name)
  1163. }
  1164. }
  1165. c.sendf(":%s CAP %s LIST :%s", serverName, a.target,
  1166. strings.Join(caps, " "))
  1167. }
  1168. func ircDecodeCapability(name string) uint {
  1169. for _, cap := range ircCapTable {
  1170. if cap.name == name {
  1171. return cap.flag
  1172. }
  1173. }
  1174. return 0
  1175. }
  1176. func (c *client) handleCAPREQ(a *ircCapArgs) {
  1177. c.capNegotiating = true
  1178. newCaps := c.capsEnabled
  1179. ok := true
  1180. for _, param := range a.params {
  1181. removing := false
  1182. name := param
  1183. if name[:1] == "-" {
  1184. removing = true
  1185. name = name[1:]
  1186. }
  1187. if cap := ircDecodeCapability(name); cap == 0 {
  1188. ok = false
  1189. } else if removing {
  1190. newCaps &= ^cap
  1191. } else {
  1192. newCaps |= cap
  1193. }
  1194. }
  1195. if ok {
  1196. c.capsEnabled = newCaps
  1197. c.sendf(":%s CAP %s ACK :%s", serverName, a.target, a.fullParams)
  1198. } else {
  1199. c.sendf(":%s CAP %s NAK :%s", serverName, a.target, a.fullParams)
  1200. }
  1201. }
  1202. func (c *client) handleCAPACK(a *ircCapArgs) {
  1203. if len(a.params) > 0 {
  1204. c.sendReply(ERR_INVALIDCAPCMD, a.subcommand,
  1205. "No acknowledgable capabilities supported")
  1206. }
  1207. }
  1208. func (c *client) handleCAPEND(a *ircCapArgs) {
  1209. c.capNegotiating = false
  1210. c.tryFinishRegistration()
  1211. }
  1212. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1213. var ircCapHandlers = map[string]func(*client, *ircCapArgs){
  1214. "LS": (*client).handleCAPLS,
  1215. "LIST": (*client).handleCAPLIST,
  1216. "REQ": (*client).handleCAPREQ,
  1217. "ACK": (*client).handleCAPACK,
  1218. "END": (*client).handleCAPEND,
  1219. }
  1220. // XXX: Maybe these also deserve to be methods for client? They operate on
  1221. // global state, though.
  1222. func ircHandleCAP(msg *message, c *client) {
  1223. if len(msg.params) < 1 {
  1224. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  1225. return
  1226. }
  1227. args := &ircCapArgs{
  1228. target: c.nicknameOrStar(),
  1229. subcommand: msg.params[0],
  1230. fullParams: "",
  1231. params: []string{},
  1232. }
  1233. if len(msg.params) > 1 {
  1234. args.fullParams = msg.params[1]
  1235. args.params = splitString(args.fullParams, " ", true)
  1236. }
  1237. if fn, ok := ircCapHandlers[ircToCanon(args.subcommand)]; !ok {
  1238. c.sendReply(ERR_INVALIDCAPCMD, args.subcommand,
  1239. "Invalid CAP subcommand")
  1240. } else {
  1241. fn(c, args)
  1242. }
  1243. }
  1244. func ircHandlePASS(msg *message, c *client) {
  1245. if c.registered {
  1246. c.sendReply(ERR_ALREADYREGISTERED)
  1247. } else if len(msg.params) < 1 {
  1248. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  1249. }
  1250. // We have TLS client certificates for this purpose; ignoring.
  1251. }
  1252. func ircHandleNICK(msg *message, c *client) {
  1253. if len(msg.params) < 1 {
  1254. c.sendReply(ERR_NONICKNAMEGIVEN)
  1255. return
  1256. }
  1257. nickname := msg.params[0]
  1258. if !ircIsValidNickname(nickname) {
  1259. c.sendReply(ERR_ERRONEOUSNICKNAME, nickname)
  1260. return
  1261. }
  1262. nicknameCanon := ircToCanon(nickname)
  1263. if client, ok := users[nicknameCanon]; ok && client != c {
  1264. c.sendReply(ERR_NICKNAMEINUSE, nickname)
  1265. return
  1266. }
  1267. if c.registered {
  1268. c.addToWhowas()
  1269. message := fmt.Sprintf(":%s!%s@%s NICK :%s",
  1270. c.nickname, c.username, c.hostname, nickname)
  1271. ircNotifyRoommates(c, message)
  1272. c.send(message)
  1273. }
  1274. // Release the old nickname and allocate a new one.
  1275. if c.nickname != "" {
  1276. delete(users, ircToCanon(c.nickname))
  1277. }
  1278. c.nickname = nickname
  1279. users[nicknameCanon] = c
  1280. c.tryFinishRegistration()
  1281. }
  1282. func ircHandleUSER(msg *message, c *client) {
  1283. if c.registered {
  1284. c.sendReply(ERR_ALREADYREGISTERED)
  1285. return
  1286. }
  1287. if len(msg.params) < 4 {
  1288. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  1289. return
  1290. }
  1291. username, mode, realname := msg.params[0], msg.params[1], msg.params[3]
  1292. // Unfortunately, the protocol doesn't give us any means of rejecting it.
  1293. if !ircIsValidUsername(username) {
  1294. username = "*"
  1295. }
  1296. c.username = username
  1297. c.realname = realname
  1298. c.mode = 0
  1299. if m, err := strconv.ParseUint(mode, 10, 32); err != nil {
  1300. if 0 != m&4 {
  1301. c.mode |= ircUserModeRxWallops
  1302. }
  1303. if 0 != m&8 {
  1304. c.mode |= ircUserModeInvisible
  1305. }
  1306. }
  1307. c.tryFinishRegistration()
  1308. }
  1309. func ircHandleUSERHOST(msg *message, c *client) {
  1310. if len(msg.params) < 1 {
  1311. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  1312. return
  1313. }
  1314. var reply []byte
  1315. for i := 0; i < 5 && i < len(msg.params); i++ {
  1316. nick := msg.params[i]
  1317. target := users[ircToCanon(nick)]
  1318. if target == nil {
  1319. continue
  1320. }
  1321. if i != 0 {
  1322. reply = append(reply, ' ')
  1323. }
  1324. reply = append(reply, nick...)
  1325. if 0 != target.mode&ircUserModeOperator {
  1326. reply = append(reply, '*')
  1327. }
  1328. if target.awayMessage != "" {
  1329. reply = append(reply, "=-"...)
  1330. } else {
  1331. reply = append(reply, "=+"...)
  1332. }
  1333. reply = append(reply, (target.username + "@" + target.hostname)...)
  1334. }
  1335. c.sendReply(RPL_USERHOST, string(reply))
  1336. }
  1337. func ircHandleLUSERS(msg *message, c *client) {
  1338. if len(msg.params) > 1 && !ircIsThisMe(msg.params[1]) {
  1339. c.sendReply(ERR_NOSUCHSERVER, msg.params[1])
  1340. return
  1341. }
  1342. c.sendLUSERS()
  1343. }
  1344. func ircHandleMOTD(msg *message, c *client) {
  1345. if len(msg.params) > 0 && !ircIsThisMe(msg.params[0]) {
  1346. c.sendReply(ERR_NOSUCHSERVER, msg.params[1])
  1347. return
  1348. }
  1349. c.sendMOTD()
  1350. }
  1351. func ircHandlePING(msg *message, c *client) {
  1352. // XXX: The RFC is pretty incomprehensible about the exact usage.
  1353. if len(msg.params) > 1 && !ircIsThisMe(msg.params[1]) {
  1354. c.sendReply(ERR_NOSUCHSERVER, msg.params[1])
  1355. } else if len(msg.params) < 1 {
  1356. c.sendReply(ERR_NOORIGIN)
  1357. } else {
  1358. c.sendf(":%s PONG :%s", serverName, msg.params[0])
  1359. }
  1360. }
  1361. func ircHandlePONG(msg *message, c *client) {
  1362. // We are the only server, so we don't have to care too much.
  1363. if len(msg.params) < 1 {
  1364. c.sendReply(ERR_NOORIGIN)
  1365. return
  1366. }
  1367. // Set a new timer to send another PING
  1368. c.setPingTimer()
  1369. }
  1370. func ircHandleQUIT(msg *message, c *client) {
  1371. reason := c.nickname
  1372. if len(msg.params) > 0 {
  1373. reason = msg.params[0]
  1374. }
  1375. c.closeLink("Quit: " + reason)
  1376. }
  1377. func ircHandleTIME(msg *message, c *client) {
  1378. if len(msg.params) > 0 && !ircIsThisMe(msg.params[0]) {
  1379. c.sendReply(ERR_NOSUCHSERVER, msg.params[0])
  1380. return
  1381. }
  1382. c.sendReply(RPL_TIME, serverName,
  1383. time.Now().Format("Mon Jan _2 2006 15:04:05"))
  1384. }
  1385. func ircHandleVERSION(msg *message, c *client) {
  1386. if len(msg.params) > 0 && !ircIsThisMe(msg.params[0]) {
  1387. c.sendReply(ERR_NOSUCHSERVER, msg.params[0])
  1388. return
  1389. }
  1390. postVersion := 0
  1391. if debugMode {
  1392. postVersion = 1
  1393. }
  1394. c.sendReply(RPL_VERSION, projectVersion, postVersion, serverName,
  1395. projectName+" "+projectVersion)
  1396. c.sendISUPPORT()
  1397. }
  1398. func ircChannelMulticast(ch *channel, msg string, except *client) {
  1399. for c := range ch.userModes {
  1400. if c != except {
  1401. c.send(msg)
  1402. }
  1403. }
  1404. }
  1405. func ircModifyMode(mask *uint, mode uint, add bool) bool {
  1406. orig := *mask
  1407. if add {
  1408. *mask |= mode
  1409. } else {
  1410. *mask &= ^mode
  1411. }
  1412. return *mask != orig
  1413. }
  1414. func ircUpdateUserMode(c *client, newMode uint) {
  1415. oldMode := c.mode
  1416. c.mode = newMode
  1417. added, removed := newMode & ^oldMode, oldMode & ^newMode
  1418. var diff []byte
  1419. if added != 0 {
  1420. diff = append(diff, '+')
  1421. diff = ircAppendClientModes(added, diff)
  1422. }
  1423. if removed != 0 {
  1424. diff = append(diff, '-')
  1425. diff = ircAppendClientModes(removed, diff)
  1426. }
  1427. if len(diff) > 0 {
  1428. c.sendf(":%s MODE %s :%s", c.nickname, c.nickname, string(diff))
  1429. }
  1430. }
  1431. func ircHandleUserModeChange(c *client, modeString string) {
  1432. newMode := c.mode
  1433. adding := true
  1434. for _, flag := range modeString {
  1435. switch flag {
  1436. case '+':
  1437. adding = true
  1438. case '-':
  1439. adding = false
  1440. case 'a':
  1441. // Ignore, the client should use AWAY.
  1442. case 'i':
  1443. ircModifyMode(&newMode, ircUserModeInvisible, adding)
  1444. case 'w':
  1445. ircModifyMode(&newMode, ircUserModeRxWallops, adding)
  1446. case 'r':
  1447. // It's not possible ot un-restrict yourself.
  1448. if adding {
  1449. newMode |= ircUserModeRestricted
  1450. }
  1451. case 'o':
  1452. if !adding {
  1453. newMode &= ^ircUserModeOperator
  1454. } else if operators[c.tlsCertFingerprint] {
  1455. newMode |= ircUserModeOperator
  1456. } else {
  1457. c.sendf(":%s NOTICE %s :Either you're not using an TLS"+
  1458. " client certificate, or the fingerprint doesn't match",
  1459. serverName, c.nickname)
  1460. }
  1461. case 's':
  1462. ircModifyMode(&newMode, ircUserModeRxServerNotices, adding)
  1463. default:
  1464. c.sendReply(ERR_UMODEUNKNOWNFLAG)
  1465. return
  1466. }
  1467. }
  1468. ircUpdateUserMode(c, newMode)
  1469. }
  1470. func ircSendChannelList(c *client, channelName string, list []string,
  1471. reply, endReply int) {
  1472. for _, line := range list {
  1473. c.sendReply(reply, channelName, line)
  1474. }
  1475. c.sendReply(endReply, channelName)
  1476. }
  1477. func ircCheckExpandUserMask(mask string) string {
  1478. var result []byte
  1479. result = append(result, mask...)
  1480. // Make sure it is a complete mask.
  1481. if bytes.IndexByte(result, '!') < 0 {
  1482. result = append(result, "!*"...)
  1483. }
  1484. if bytes.IndexByte(result, '@') < 0 {
  1485. result = append(result, "@*"...)
  1486. }
  1487. // And validate whatever the result is.
  1488. s := string(result)
  1489. if !ircIsValidUserMask(s) {
  1490. return ""
  1491. }
  1492. return s
  1493. }
  1494. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1495. // Channel MODE command handling. This is by far the worst command to implement
  1496. // from the whole RFC; don't blame me if it doesn't work exactly as expected.
  1497. type modeProcessor struct {
  1498. params []string // mode string parameters
  1499. c *client // who does the changes
  1500. ch *channel // the channel we're modifying
  1501. present bool // c present on ch
  1502. modes uint // channel user modes
  1503. adding bool // currently adding modes
  1504. modeChar byte // currently processed mode char
  1505. added []byte // added modes
  1506. removed []byte // removed modes
  1507. output *[]byte // "added" or "removed"
  1508. addedParams []string // params for added modes
  1509. removedParams []string // params for removed modes
  1510. outputParams *[]string // "addedParams" or "removedParams"
  1511. }
  1512. func (mp *modeProcessor) nextParam() string {
  1513. if len(mp.params) == 0 {
  1514. return ""
  1515. }
  1516. param := mp.params[0]
  1517. mp.params = mp.params[1:]
  1518. return param
  1519. }
  1520. func (mp *modeProcessor) checkOperator() bool {
  1521. if (mp.present && 0 != mp.modes&ircChanModeOperator) ||
  1522. 0 != mp.c.mode&ircUserModeOperator {
  1523. return true
  1524. }
  1525. mp.c.sendReply(ERR_CHANOPRIVSNEEDED, mp.ch.name)
  1526. return false
  1527. }
  1528. func (mp *modeProcessor) doUser(mode uint) {
  1529. target := mp.nextParam()
  1530. if !mp.checkOperator() || target == "" {
  1531. return
  1532. }
  1533. if client := users[ircToCanon(target)]; client == nil {
  1534. mp.c.sendReply(ERR_NOSUCHNICK, target)
  1535. } else if modes, present := mp.ch.userModes[client]; !present {
  1536. mp.c.sendReply(ERR_USERNOTINCHANNEL, target, mp.ch.name)
  1537. } else if ircModifyMode(&modes, mode, mp.adding) {
  1538. mp.ch.userModes[client] = modes
  1539. *mp.output = append(*mp.output, mp.modeChar)
  1540. *mp.outputParams = append(*mp.outputParams, client.nickname)
  1541. }
  1542. }
  1543. func (mp *modeProcessor) doChan(mode uint) bool {
  1544. if !mp.checkOperator() || !ircModifyMode(&mp.ch.modes, mode, mp.adding) {
  1545. return false
  1546. }
  1547. *mp.output = append(*mp.output, mp.modeChar)
  1548. return true
  1549. }
  1550. func (mp *modeProcessor) doChanRemove(modeChar byte, mode uint) {
  1551. if mp.adding && ircModifyMode(&mp.ch.modes, mode, false) {
  1552. mp.removed = append(mp.removed, modeChar)
  1553. }
  1554. }
  1555. func (mp *modeProcessor) doList(list *[]string, listMsg, endMsg int) {
  1556. target := mp.nextParam()
  1557. if target == "" {
  1558. if mp.adding {
  1559. ircSendChannelList(mp.c, mp.ch.name, *list, listMsg, endMsg)
  1560. }
  1561. return
  1562. }
  1563. if !mp.checkOperator() {
  1564. return
  1565. }
  1566. mask := ircCheckExpandUserMask(target)
  1567. if mask == "" {
  1568. return
  1569. }
  1570. var i int
  1571. for i = 0; i < len(*list); i++ {
  1572. if ircEqual((*list)[i], mask) {
  1573. break
  1574. }
  1575. }
  1576. found := i < len(*list)
  1577. if found != mp.adding {
  1578. if mp.adding {
  1579. *list = append(*list, mask)
  1580. } else {
  1581. *list = append((*list)[:i], (*list)[i+1:]...)
  1582. }
  1583. *mp.output = append(*mp.output, mp.modeChar)
  1584. *mp.outputParams = append(*mp.outputParams, mask)
  1585. }
  1586. }
  1587. func (mp *modeProcessor) doKey() {
  1588. target := mp.nextParam()
  1589. if !mp.checkOperator() || target == "" {
  1590. return
  1591. }
  1592. if !mp.adding {
  1593. if mp.ch.key == "" || !ircEqual(target, mp.ch.key) {
  1594. return
  1595. }
  1596. mp.removed = append(mp.removed, mp.modeChar)
  1597. mp.removedParams = append(mp.removedParams, mp.ch.key)
  1598. mp.ch.key = ""
  1599. } else if !ircIsValidKey(target) {
  1600. // TODO: We should notify the user somehow.
  1601. return
  1602. } else if mp.ch.key != "" {
  1603. mp.c.sendReply(ERR_KEYSET, mp.ch.name)
  1604. } else {
  1605. mp.ch.key = target
  1606. mp.added = append(mp.added, mp.modeChar)
  1607. mp.addedParams = append(mp.addedParams, mp.ch.key)
  1608. }
  1609. }
  1610. func (mp *modeProcessor) doLimit() {
  1611. if !mp.checkOperator() {
  1612. return
  1613. }
  1614. if !mp.adding {
  1615. if mp.ch.userLimit == -1 {
  1616. return
  1617. }
  1618. mp.ch.userLimit = -1
  1619. mp.removed = append(mp.removed, mp.modeChar)
  1620. } else if target := mp.nextParam(); target != "" {
  1621. if x, err := strconv.ParseInt(target, 10, 32); err == nil && x > 0 {
  1622. mp.ch.userLimit = int(x)
  1623. mp.added = append(mp.added, mp.modeChar)
  1624. mp.addedParams = append(mp.addedParams, target)
  1625. }
  1626. }
  1627. }
  1628. func (mp *modeProcessor) step(modeChar byte) bool {
  1629. mp.modeChar = modeChar
  1630. switch mp.modeChar {
  1631. case '+':
  1632. mp.adding = true
  1633. mp.output = &mp.added
  1634. mp.outputParams = &mp.addedParams
  1635. case '-':
  1636. mp.adding = false
  1637. mp.output = &mp.removed
  1638. mp.outputParams = &mp.removedParams
  1639. case 'o':
  1640. mp.doUser(ircChanModeOperator)
  1641. case 'v':
  1642. mp.doUser(ircChanModeVoice)
  1643. case 'i':
  1644. mp.doChan(ircChanModeInviteOnly)
  1645. case 'm':
  1646. mp.doChan(ircChanModeModerated)
  1647. case 'n':
  1648. mp.doChan(ircChanModeNoOutsideMsgs)
  1649. case 'q':
  1650. mp.doChan(ircChanModeQuiet)
  1651. case 't':
  1652. mp.doChan(ircChanModeProtectedTopic)
  1653. case 'p':
  1654. if mp.doChan(ircChanModePrivate) {
  1655. mp.doChanRemove('s', ircChanModeSecret)
  1656. }
  1657. case 's':
  1658. if mp.doChan(ircChanModeSecret) {
  1659. mp.doChanRemove('p', ircChanModePrivate)
  1660. }
  1661. case 'b':
  1662. mp.doList(&mp.ch.banList, RPL_BANLIST, RPL_ENDOFBANLIST)
  1663. case 'e':
  1664. mp.doList(&mp.ch.banList, RPL_EXCEPTLIST, RPL_ENDOFEXCEPTLIST)
  1665. case 'I':
  1666. mp.doList(&mp.ch.banList, RPL_INVITELIST, RPL_ENDOFINVITELIST)
  1667. case 'k':
  1668. mp.doKey()
  1669. case 'l':
  1670. mp.doLimit()
  1671. default:
  1672. // It's not safe to continue, results could be undesired.
  1673. mp.c.sendReply(ERR_UNKNOWNMODE, modeChar, mp.ch.name)
  1674. return false
  1675. }
  1676. return true
  1677. }
  1678. func ircHandleChanModeChange(c *client, ch *channel, params []string) {
  1679. modes, present := ch.userModes[c]
  1680. mp := &modeProcessor{
  1681. c: c,
  1682. ch: ch,
  1683. present: present,
  1684. modes: modes,
  1685. params: params,
  1686. }
  1687. Outer:
  1688. for {
  1689. modeString := mp.nextParam()
  1690. if modeString == "" {
  1691. break
  1692. }
  1693. mp.step('+')
  1694. for _, modeChar := range []byte(modeString) {
  1695. if !mp.step(modeChar) {
  1696. break Outer
  1697. }
  1698. }
  1699. }
  1700. // TODO: Limit to three changes with parameter per command.
  1701. if len(mp.added) > 0 || len(mp.removed) > 0 {
  1702. buf := []byte(fmt.Sprintf(":%s!%s@%s MODE %s ",
  1703. mp.c.nickname, mp.c.username, mp.c.hostname, mp.ch.name))
  1704. if len(mp.added) > 0 {
  1705. buf = append(buf, '+')
  1706. buf = append(buf, mp.added...)
  1707. }
  1708. if len(mp.removed) > 0 {
  1709. buf = append(buf, '-')
  1710. buf = append(buf, mp.removed...)
  1711. }
  1712. for _, param := range mp.addedParams {
  1713. buf = append(buf, ' ')
  1714. buf = append(buf, param...)
  1715. }
  1716. for _, param := range mp.removedParams {
  1717. buf = append(buf, ' ')
  1718. buf = append(buf, param...)
  1719. }
  1720. ircChannelMulticast(mp.ch, string(buf), nil)
  1721. }
  1722. }
  1723. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1724. func ircHandleMODE(msg *message, c *client) {
  1725. if len(msg.params) < 1 {
  1726. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  1727. return
  1728. }
  1729. target := msg.params[0]
  1730. client := users[ircToCanon(target)]
  1731. ch := channels[ircToCanon(target)]
  1732. if client != nil {
  1733. if !ircEqual(target, c.nickname) {
  1734. c.sendReply(ERR_USERSDONTMATCH)
  1735. return
  1736. }
  1737. if len(msg.params) < 2 {
  1738. c.sendReply(RPL_UMODEIS, c.getMode())
  1739. } else {
  1740. ircHandleUserModeChange(c, msg.params[1])
  1741. }
  1742. } else if ch != nil {
  1743. if len(msg.params) < 2 {
  1744. _, present := ch.userModes[c]
  1745. c.sendReply(RPL_CHANNELMODEIS, target, ch.getMode(present))
  1746. c.sendReply(RPL_CREATIONTIME, target, ch.created.Unix())
  1747. } else {
  1748. ircHandleChanModeChange(c, ch, msg.params[1:])
  1749. }
  1750. } else {
  1751. c.sendReply(ERR_NOSUCHNICK, target)
  1752. }
  1753. }
  1754. func ircHandleUserMessage(msg *message, c *client,
  1755. command string, allowAwayReply bool) {
  1756. if len(msg.params) < 1 {
  1757. c.sendReply(ERR_NORECIPIENT, msg.command)
  1758. return
  1759. }
  1760. if len(msg.params) < 2 || msg.params[1] == "" {
  1761. c.sendReply(ERR_NOTEXTTOSEND)
  1762. return
  1763. }
  1764. target, text := msg.params[0], msg.params[1]
  1765. message := fmt.Sprintf(":%s!%s@%s %s %s :%s",
  1766. c.nickname, c.username, c.hostname, command, target, text)
  1767. if client := users[ircToCanon(target)]; client != nil {
  1768. client.send(message)
  1769. if allowAwayReply && client.awayMessage != "" {
  1770. c.sendReply(RPL_AWAY, target, client.awayMessage)
  1771. }
  1772. // Acknowledging a message from the client to itself would be silly.
  1773. if client != c && (0 != c.capsEnabled&ircCapEchoMessage) {
  1774. c.send(message)
  1775. }
  1776. } else if ch := channels[ircToCanon(target)]; ch != nil {
  1777. modes, present := ch.userModes[c]
  1778. outsider := !present && 0 != ch.modes&ircChanModeNoOutsideMsgs
  1779. moderated := 0 != ch.modes&ircChanModeModerated &&
  1780. 0 == modes&(ircChanModeVoice|ircChanModeOperator)
  1781. banned := c.inMaskList(ch.banList) && !c.inMaskList(ch.exceptionList)
  1782. if outsider || moderated || banned {
  1783. c.sendReply(ERR_CANNOTSENDTOCHAN, target)
  1784. return
  1785. }
  1786. except := c
  1787. if 0 != c.capsEnabled&ircCapEchoMessage {
  1788. except = nil
  1789. }
  1790. ircChannelMulticast(ch, message, except)
  1791. } else {
  1792. c.sendReply(ERR_NOSUCHNICK, target)
  1793. }
  1794. }
  1795. func ircHandlePRIVMSG(msg *message, c *client) {
  1796. ircHandleUserMessage(msg, c, "PRIVMSG", true /* allowAwayReply */)
  1797. c.lastActive = time.Now()
  1798. }
  1799. func ircHandleNOTICE(msg *message, c *client) {
  1800. ircHandleUserMessage(msg, c, "NOTICE", false /* allowAwayReply */)
  1801. }
  1802. func ircHandleLIST(msg *message, c *client) {
  1803. if len(msg.params) > 1 && !ircIsThisMe(msg.params[1]) {
  1804. c.sendReply(ERR_NOSUCHSERVER, msg.params[1])
  1805. return
  1806. }
  1807. // XXX: Maybe we should skip ircUserModeInvisible from user counts.
  1808. if len(msg.params) == 0 {
  1809. for _, ch := range channels {
  1810. if _, present := ch.userModes[c]; present ||
  1811. 0 == ch.modes&(ircChanModePrivate|ircChanModeSecret) {
  1812. c.sendReply(RPL_LIST, ch.name, len(ch.userModes), ch.topic)
  1813. }
  1814. }
  1815. } else {
  1816. for _, target := range splitString(msg.params[0], ",", true) {
  1817. if ch := channels[ircToCanon(target)]; ch != nil &&
  1818. 0 == ch.modes&ircChanModeSecret {
  1819. c.sendReply(RPL_LIST, ch.name, len(ch.userModes), ch.topic)
  1820. }
  1821. }
  1822. }
  1823. c.sendReply(RPL_LISTEND)
  1824. }
  1825. func ircAppendPrefixes(c *client, modes uint, buf []byte) []byte {
  1826. var all []byte
  1827. if 0 != modes&ircChanModeOperator {
  1828. all = append(all, '@')
  1829. }
  1830. if 0 != modes&ircChanModeVoice {
  1831. all = append(all, '+')
  1832. }
  1833. if len(all) > 0 {
  1834. if 0 != c.capsEnabled&ircCapMultiPrefix {
  1835. buf = append(buf, all...)
  1836. } else {
  1837. buf = append(buf, all[0])
  1838. }
  1839. }
  1840. return buf
  1841. }
  1842. func ircMakeRPLNAMREPLYItem(c, target *client, modes uint) string {
  1843. result := string(ircAppendPrefixes(c, modes, nil)) + target.nickname
  1844. if 0 != c.capsEnabled&ircCapUserhostInNames {
  1845. result += fmt.Sprintf("!%s@%s", target.username, target.hostname)
  1846. }
  1847. return result
  1848. }
  1849. func ircSendRPLNAMREPLY(c *client, ch *channel, usedNicks map[*client]bool) {
  1850. kind := '='
  1851. if 0 != ch.modes&ircChanModeSecret {
  1852. kind = '@'
  1853. } else if 0 != ch.modes&ircChanModePrivate {
  1854. kind = '*'
  1855. }
  1856. _, present := ch.userModes[c]
  1857. var nicks []string
  1858. for client, modes := range ch.userModes {
  1859. if !present && 0 != client.mode&ircUserModeInvisible {
  1860. continue
  1861. }
  1862. if usedNicks != nil {
  1863. usedNicks[client] = true
  1864. }
  1865. nicks = append(nicks, ircMakeRPLNAMREPLYItem(c, client, modes))
  1866. }
  1867. c.sendReplyVector(RPL_NAMREPLY, nicks, kind, ch.name, "")
  1868. }
  1869. func ircSendDisassociatedNames(c *client, usedNicks map[*client]bool) {
  1870. var nicks []string
  1871. for _, client := range users {
  1872. if 0 == client.mode&ircUserModeInvisible && !usedNicks[client] {
  1873. nicks = append(nicks, ircMakeRPLNAMREPLYItem(c, client, 0))
  1874. }
  1875. }
  1876. if len(nicks) > 0 {
  1877. c.sendReplyVector(RPL_NAMREPLY, nicks, '*', "*", "")
  1878. }
  1879. }
  1880. func ircHandleNAMES(msg *message, c *client) {
  1881. if len(msg.params) > 1 && !ircIsThisMe(msg.params[1]) {
  1882. c.sendReply(ERR_NOSUCHSERVER, msg.params[1])
  1883. return
  1884. }
  1885. if len(msg.params) == 0 {
  1886. usedNicks := make(map[*client]bool)
  1887. for _, ch := range channels {
  1888. if _, present := ch.userModes[c]; present ||
  1889. 0 == ch.modes&(ircChanModePrivate|ircChanModeSecret) {
  1890. ircSendRPLNAMREPLY(c, ch, usedNicks)
  1891. }
  1892. }
  1893. // Also send all visible users we haven't listed yet.
  1894. ircSendDisassociatedNames(c, usedNicks)
  1895. c.sendReply(RPL_ENDOFNAMES, "*")
  1896. } else {
  1897. for _, target := range splitString(msg.params[0], ",", true) {
  1898. if ch := channels[ircToCanon(target)]; ch == nil {
  1899. } else if _, present := ch.userModes[c]; present ||
  1900. 0 == ch.modes&ircChanModeSecret {
  1901. ircSendRPLNAMREPLY(c, ch, nil)
  1902. c.sendReply(RPL_ENDOFNAMES, target)
  1903. }
  1904. }
  1905. }
  1906. }
  1907. func ircSendRPLWHOREPLY(c *client, ch *channel, target *client) {
  1908. var chars []byte
  1909. if target.awayMessage != "" {
  1910. chars = append(chars, 'G')
  1911. } else {
  1912. chars = append(chars, 'H')
  1913. }
  1914. if 0 != target.mode&ircUserModeOperator {
  1915. chars = append(chars, '*')
  1916. }
  1917. channelName := "*"
  1918. if ch != nil {
  1919. channelName = ch.name
  1920. if modes, present := ch.userModes[target]; present {
  1921. chars = ircAppendPrefixes(c, modes, chars)
  1922. }
  1923. }
  1924. c.sendReply(RPL_WHOREPLY, channelName,
  1925. target.username, target.hostname, serverName,
  1926. target.nickname, string(chars), 0 /* hop count */, target.realname)
  1927. }
  1928. func ircMatchSendRPLWHOREPLY(c, target *client, mask string) {
  1929. isRoommate := false
  1930. for _, ch := range channels {
  1931. _, presentClient := ch.userModes[c]
  1932. _, presentTarget := ch.userModes[target]
  1933. if presentClient && presentTarget {
  1934. isRoommate = true
  1935. break
  1936. }
  1937. }
  1938. if !isRoommate && 0 != target.mode&ircUserModeInvisible {
  1939. return
  1940. }
  1941. if !ircFnmatch(mask, target.hostname) &&
  1942. !ircFnmatch(mask, target.nickname) &&
  1943. !ircFnmatch(mask, target.realname) &&
  1944. !ircFnmatch(mask, serverName) {
  1945. return
  1946. }
  1947. // Try to find a channel they're on that's visible to us.
  1948. var userCh *channel
  1949. for _, ch := range channels {
  1950. _, presentClient := ch.userModes[c]
  1951. _, presentTarget := ch.userModes[target]
  1952. if presentTarget && (presentClient ||
  1953. 0 == ch.modes&(ircChanModePrivate|ircChanModeSecret)) {
  1954. userCh = ch
  1955. break
  1956. }
  1957. }
  1958. ircSendRPLWHOREPLY(c, userCh, target)
  1959. }
  1960. func ircHandleWHO(msg *message, c *client) {
  1961. onlyOps := len(msg.params) > 1 && msg.params[1] == "o"
  1962. shownMask, usedMask := "*", "*"
  1963. if len(msg.params) > 0 {
  1964. shownMask = msg.params[0]
  1965. if shownMask != "0" {
  1966. usedMask = shownMask
  1967. }
  1968. }
  1969. if ch := channels[ircToCanon(usedMask)]; ch != nil {
  1970. _, present := ch.userModes[c]
  1971. if present || 0 == ch.modes&ircChanModeSecret {
  1972. for client := range ch.userModes {
  1973. if (present || 0 == client.mode&ircUserModeInvisible) &&
  1974. (!onlyOps || 0 != client.mode&ircUserModeOperator) {
  1975. ircSendRPLWHOREPLY(c, ch, client)
  1976. }
  1977. }
  1978. }
  1979. } else {
  1980. for _, client := range users {
  1981. if !onlyOps || 0 != client.mode&ircUserModeOperator {
  1982. ircMatchSendRPLWHOREPLY(c, client, usedMask)
  1983. }
  1984. }
  1985. }
  1986. c.sendReply(RPL_ENDOFWHO, shownMask)
  1987. }
  1988. func ircSendWHOISReply(c, target *client) {
  1989. nick := target.nickname
  1990. c.sendReply(RPL_WHOISUSER, nick,
  1991. target.username, target.hostname, target.realname)
  1992. c.sendReply(RPL_WHOISSERVER, nick, serverName, config["server_info"])
  1993. if 0 != target.mode&ircUserModeOperator {
  1994. c.sendReply(RPL_WHOISOPERATOR, nick)
  1995. }
  1996. c.sendReply(RPL_WHOISIDLE, nick,
  1997. time.Now().Sub(target.lastActive)/time.Second)
  1998. if target.awayMessage != "" {
  1999. c.sendReply(RPL_AWAY, nick, target.awayMessage)
  2000. }
  2001. var chans []string
  2002. for _, ch := range channels {
  2003. _, presentClient := ch.userModes[c]
  2004. modes, presentTarget := ch.userModes[target]
  2005. if presentTarget && (presentClient ||
  2006. 0 == ch.modes&(ircChanModePrivate|ircChanModeSecret)) {
  2007. // TODO: Deduplicate, ircAppendPrefixes just also cuts prefixes.
  2008. var all []byte
  2009. if 0 != modes&ircChanModeOperator {
  2010. all = append(all, '@')
  2011. }
  2012. if 0 != modes&ircChanModeVoice {
  2013. all = append(all, '+')
  2014. }
  2015. chans = append(chans, string(all)+ch.name)
  2016. }
  2017. }
  2018. c.sendReplyVector(RPL_WHOISCHANNELS, chans, nick, "")
  2019. c.sendReply(RPL_ENDOFWHOIS, nick)
  2020. }
  2021. func ircHandleWHOIS(msg *message, c *client) {
  2022. if len(msg.params) < 1 {
  2023. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2024. return
  2025. }
  2026. if len(msg.params) > 1 && !ircIsThisMe(msg.params[0]) {
  2027. c.sendReply(ERR_NOSUCHSERVER, msg.params[0])
  2028. return
  2029. }
  2030. masksStr := msg.params[0]
  2031. if len(msg.params) > 1 {
  2032. masksStr = msg.params[1]
  2033. }
  2034. for _, mask := range splitString(masksStr, ",", true /* ignoreEmpty */) {
  2035. if strings.IndexAny(mask, "*?") < 0 {
  2036. if target := users[ircToCanon(mask)]; target == nil {
  2037. c.sendReply(ERR_NOSUCHNICK, mask)
  2038. } else {
  2039. ircSendWHOISReply(c, target)
  2040. }
  2041. } else {
  2042. found := false
  2043. for _, target := range users {
  2044. if ircFnmatch(mask, target.nickname) {
  2045. ircSendWHOISReply(c, target)
  2046. found = true
  2047. }
  2048. }
  2049. if !found {
  2050. c.sendReply(ERR_NOSUCHNICK, mask)
  2051. }
  2052. }
  2053. }
  2054. }
  2055. func ircHandleWHOWAS(msg *message, c *client) {
  2056. if len(msg.params) < 1 {
  2057. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2058. return
  2059. }
  2060. if len(msg.params) > 2 && !ircIsThisMe(msg.params[2]) {
  2061. c.sendReply(ERR_NOSUCHSERVER, msg.params[2])
  2062. return
  2063. }
  2064. // The "count" parameter is ignored, we only store one entry for a nick.
  2065. for _, nick := range splitString(msg.params[0], ",", true) {
  2066. if info := whowas[ircToCanon(nick)]; info == nil {
  2067. c.sendReply(ERR_WASNOSUCHNICK, nick)
  2068. } else {
  2069. c.sendReply(RPL_WHOWASUSER, nick,
  2070. info.username, info.hostname, info.realname)
  2071. c.sendReply(RPL_WHOISSERVER, nick,
  2072. serverName, config["server_info"])
  2073. }
  2074. c.sendReply(RPL_ENDOFWHOWAS, nick)
  2075. }
  2076. }
  2077. func ircSendRPLTOPIC(c *client, ch *channel) {
  2078. if ch.topic == "" {
  2079. c.sendReply(RPL_NOTOPIC, ch.name)
  2080. } else {
  2081. c.sendReply(RPL_TOPIC, ch.name, ch.topic)
  2082. c.sendReply(RPL_TOPICWHOTIME,
  2083. ch.name, ch.topicWho, ch.topicTime.Unix())
  2084. }
  2085. }
  2086. func ircHandleTOPIC(msg *message, c *client) {
  2087. if len(msg.params) < 1 {
  2088. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2089. return
  2090. }
  2091. channelName := msg.params[0]
  2092. ch := channels[ircToCanon(channelName)]
  2093. if ch == nil {
  2094. c.sendReply(ERR_NOSUCHCHANNEL, channelName)
  2095. return
  2096. }
  2097. if len(msg.params) < 2 {
  2098. ircSendRPLTOPIC(c, ch)
  2099. return
  2100. }
  2101. modes, present := ch.userModes[c]
  2102. if !present {
  2103. c.sendReply(ERR_NOTONCHANNEL, channelName)
  2104. return
  2105. }
  2106. if 0 != ch.modes&ircChanModeProtectedTopic &&
  2107. 0 == modes&ircChanModeOperator {
  2108. c.sendReply(ERR_CHANOPRIVSNEEDED, channelName)
  2109. return
  2110. }
  2111. ch.topic = msg.params[1]
  2112. ch.topicWho = fmt.Sprintf("%s@%s@%s", c.nickname, c.username, c.hostname)
  2113. ch.topicTime = time.Now()
  2114. message := fmt.Sprintf(":%s!%s@%s TOPIC %s :%s",
  2115. c.nickname, c.username, c.hostname, channelName, ch.topic)
  2116. ircChannelMulticast(ch, message, nil)
  2117. }
  2118. func ircTryPart(c *client, channelName string, reason string) {
  2119. if reason == "" {
  2120. reason = c.nickname
  2121. }
  2122. ch := channels[ircToCanon(channelName)]
  2123. if ch == nil {
  2124. c.sendReply(ERR_NOSUCHCHANNEL, channelName)
  2125. return
  2126. }
  2127. if _, present := ch.userModes[c]; !present {
  2128. c.sendReply(ERR_NOTONCHANNEL, channelName)
  2129. return
  2130. }
  2131. message := fmt.Sprintf(":%s@%s@%s PART %s :%s",
  2132. c.nickname, c.username, c.hostname, channelName, reason)
  2133. if 0 == ch.modes&ircChanModeQuiet {
  2134. ircChannelMulticast(ch, message, nil)
  2135. } else {
  2136. c.send(message)
  2137. }
  2138. delete(ch.userModes, c)
  2139. ircChannelDestroyIfEmpty(ch)
  2140. }
  2141. func ircPartAllChannels(c *client) {
  2142. for _, ch := range channels {
  2143. if _, present := ch.userModes[c]; present {
  2144. ircTryPart(c, ch.name, "")
  2145. }
  2146. }
  2147. }
  2148. func ircHandlePART(msg *message, c *client) {
  2149. if len(msg.params) < 1 {
  2150. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2151. return
  2152. }
  2153. reason := ""
  2154. if len(msg.params) > 1 {
  2155. reason = msg.params[1]
  2156. }
  2157. for _, channelName := range splitString(msg.params[0], ",", true) {
  2158. ircTryPart(c, channelName, reason)
  2159. }
  2160. }
  2161. func ircTryKick(c *client, channelName, nick, reason string) {
  2162. ch := channels[ircToCanon(channelName)]
  2163. if ch == nil {
  2164. c.sendReply(ERR_NOSUCHCHANNEL, channelName)
  2165. return
  2166. }
  2167. if modes, present := ch.userModes[c]; !present {
  2168. c.sendReply(ERR_NOTONCHANNEL, channelName)
  2169. return
  2170. } else if 0 == modes&ircChanModeOperator {
  2171. c.sendReply(ERR_CHANOPRIVSNEEDED, channelName)
  2172. return
  2173. }
  2174. client := users[ircToCanon(nick)]
  2175. if _, present := ch.userModes[client]; client == nil || !present {
  2176. c.sendReply(ERR_USERNOTINCHANNEL, nick, channelName)
  2177. return
  2178. }
  2179. message := fmt.Sprintf(":%s@%s@%s KICK %s %s :%s",
  2180. c.nickname, c.username, c.hostname, channelName, nick, reason)
  2181. if 0 == ch.modes&ircChanModeQuiet {
  2182. ircChannelMulticast(ch, message, nil)
  2183. } else {
  2184. c.send(message)
  2185. }
  2186. delete(ch.userModes, client)
  2187. ircChannelDestroyIfEmpty(ch)
  2188. }
  2189. func ircHandleKICK(msg *message, c *client) {
  2190. if len(msg.params) < 2 {
  2191. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2192. return
  2193. }
  2194. reason := c.nickname
  2195. if len(msg.params) > 2 {
  2196. reason = msg.params[2]
  2197. }
  2198. targetChannels := splitString(msg.params[0], ",", true)
  2199. targetUsers := splitString(msg.params[1], ",", true)
  2200. if len(channels) == 1 {
  2201. for i := 0; i < len(targetUsers); i++ {
  2202. ircTryKick(c, targetChannels[0], targetUsers[i], reason)
  2203. }
  2204. } else {
  2205. for i := 0; i < len(channels) && i < len(targetUsers); i++ {
  2206. ircTryKick(c, targetChannels[i], targetUsers[i], reason)
  2207. }
  2208. }
  2209. }
  2210. func ircSendInviteNotifications(ch *channel, c, target *client) {
  2211. for client := range ch.userModes {
  2212. if client != target && 0 != client.capsEnabled&ircCapInviteNotify {
  2213. client.sendf(":%s!%s@%s INVITE %s %s",
  2214. c.nickname, c.username, c.hostname, target.nickname, ch.name)
  2215. }
  2216. }
  2217. }
  2218. func ircHandleINVITE(msg *message, c *client) {
  2219. if len(msg.params) < 2 {
  2220. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2221. return
  2222. }
  2223. target, channelName := msg.params[0], msg.params[1]
  2224. client := users[ircToCanon(target)]
  2225. if client == nil {
  2226. c.sendReply(ERR_NOSUCHNICK, target)
  2227. return
  2228. }
  2229. if ch := channels[ircToCanon(channelName)]; ch != nil {
  2230. invitingModes, invitingPresent := ch.userModes[c]
  2231. if !invitingPresent {
  2232. c.sendReply(ERR_NOTONCHANNEL, channelName)
  2233. return
  2234. }
  2235. if _, present := ch.userModes[client]; present {
  2236. c.sendReply(ERR_USERONCHANNEL, target, channelName)
  2237. return
  2238. }
  2239. if 0 != invitingModes&ircChanModeOperator {
  2240. client.invites[ircToCanon(channelName)] = true
  2241. } else if 0 != ch.modes&ircChanModeInviteOnly {
  2242. c.sendReply(ERR_CHANOPRIVSNEEDED, channelName)
  2243. return
  2244. }
  2245. // It's not specified when and how we should send out invite-notify.
  2246. if 0 != ch.modes&ircChanModeInviteOnly {
  2247. ircSendInviteNotifications(ch, c, client)
  2248. }
  2249. }
  2250. client.sendf(":%s!%s@%s INVITE %s %s",
  2251. c.nickname, c.username, c.hostname, client.nickname, channelName)
  2252. if client.awayMessage != "" {
  2253. c.sendReply(RPL_AWAY, client.nickname, client.awayMessage)
  2254. }
  2255. c.sendReply(RPL_INVITING, client.nickname, channelName)
  2256. }
  2257. func ircTryJoin(c *client, channelName, key string) {
  2258. ch := channels[ircToCanon(channelName)]
  2259. var userMode uint
  2260. if ch == nil {
  2261. if !ircIsValidChannelName(channelName) {
  2262. c.sendReply(ERR_BADCHANMASK, channelName)
  2263. return
  2264. }
  2265. ch = ircChannelCreate(channelName)
  2266. userMode = ircChanModeOperator
  2267. } else if _, present := ch.userModes[c]; present {
  2268. return
  2269. }
  2270. _, invitedByChanop := c.invites[ircToCanon(channelName)]
  2271. if 0 != ch.modes&ircChanModeInviteOnly && c.inMaskList(ch.inviteList) &&
  2272. !invitedByChanop {
  2273. c.sendReply(ERR_INVITEONLYCHAN, channelName)
  2274. return
  2275. }
  2276. if ch.key != "" && (key == "" || key != ch.key) {
  2277. c.sendReply(ERR_BADCHANNELKEY, channelName)
  2278. return
  2279. }
  2280. if ch.userLimit != -1 && len(ch.userModes) >= ch.userLimit {
  2281. c.sendReply(ERR_CHANNELISFULL, channelName)
  2282. return
  2283. }
  2284. if c.inMaskList(ch.banList) && !c.inMaskList(ch.exceptionList) &&
  2285. !invitedByChanop {
  2286. c.sendReply(ERR_BANNEDFROMCHAN, channelName)
  2287. return
  2288. }
  2289. // Destroy any invitation as there's no other way to get rid of it.
  2290. delete(c.invites, ircToCanon(channelName))
  2291. ch.userModes[c] = userMode
  2292. message := fmt.Sprintf(":%s!%s@%s JOIN %s",
  2293. c.nickname, c.username, c.hostname, channelName)
  2294. if 0 == ch.modes&ircChanModeQuiet {
  2295. ircChannelMulticast(ch, message, nil)
  2296. } else {
  2297. c.send(message)
  2298. }
  2299. ircSendRPLTOPIC(c, ch)
  2300. ircSendRPLNAMREPLY(c, ch, nil)
  2301. c.sendReply(RPL_ENDOFNAMES, ch.name)
  2302. }
  2303. func ircHandleJOIN(msg *message, c *client) {
  2304. if len(msg.params) < 1 {
  2305. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2306. return
  2307. }
  2308. if msg.params[0] == "0" {
  2309. ircPartAllChannels(c)
  2310. return
  2311. }
  2312. targetChannels := splitString(msg.params[0], ",", true)
  2313. var keys []string
  2314. if len(msg.params) > 1 {
  2315. keys = splitString(msg.params[1], ",", true)
  2316. }
  2317. for i, name := range targetChannels {
  2318. key := ""
  2319. if i < len(keys) {
  2320. key = keys[i]
  2321. }
  2322. ircTryJoin(c, name, key)
  2323. }
  2324. }
  2325. func ircHandleSUMMON(msg *message, c *client) {
  2326. c.sendReply(ERR_SUMMONDISABLED)
  2327. }
  2328. func ircHandleUSERS(msg *message, c *client) {
  2329. c.sendReply(ERR_USERSDISABLED)
  2330. }
  2331. func ircHandleAWAY(msg *message, c *client) {
  2332. if len(msg.params) < 1 {
  2333. c.awayMessage = ""
  2334. c.sendReply(RPL_UNAWAY)
  2335. } else {
  2336. c.awayMessage = msg.params[0]
  2337. c.sendReply(RPL_NOWAWAY)
  2338. }
  2339. }
  2340. func ircHandleISON(msg *message, c *client) {
  2341. if len(msg.params) < 1 {
  2342. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2343. return
  2344. }
  2345. var on []string
  2346. for _, nick := range msg.params {
  2347. if client := users[ircToCanon(nick)]; client != nil {
  2348. on = append(on, nick)
  2349. }
  2350. }
  2351. c.sendReply(RPL_ISON, strings.Join(on, " "))
  2352. }
  2353. func ircHandleADMIN(msg *message, c *client) {
  2354. if len(msg.params) > 0 && !ircIsThisMe(msg.params[0]) {
  2355. c.sendReply(ERR_NOSUCHSERVER, msg.params[0])
  2356. return
  2357. }
  2358. c.sendReply(ERR_NOADMININFO, serverName)
  2359. }
  2360. func ircHandleStatsLinks(c *client, msg *message) {
  2361. // There is only an "l" query in RFC 2812 but we cannot link,
  2362. // so instead we provide the "L" query giving information for all users.
  2363. filter := ""
  2364. if len(msg.params) > 1 {
  2365. filter = msg.params[1]
  2366. }
  2367. for _, client := range users {
  2368. if filter != "" && !ircEqual(client.nickname, filter) {
  2369. continue
  2370. }
  2371. c.sendReply(RPL_STATSLINKINFO,
  2372. client.address, // linkname
  2373. len(client.sendQ), // sendq
  2374. client.nSentMessages, client.sentBytes/1024,
  2375. client.nReceivedMessages, client.receivedBytes/1024,
  2376. time.Now().Sub(client.opened)/time.Second)
  2377. }
  2378. }
  2379. func ircHandleStatsCommands(c *client) {
  2380. for name, handler := range ircHandlers {
  2381. if handler.nReceived > 0 {
  2382. c.sendReply(RPL_STATSCOMMANDS, name,
  2383. handler.nReceived, handler.bytesReceived, 0)
  2384. }
  2385. }
  2386. }
  2387. // We need to do it this way because of an initialization loop concerning
  2388. // ircHandlers. Workaround proposed by rsc in go #1817.
  2389. var ircHandleStatsCommandsIndirect func(c *client)
  2390. func init() {
  2391. ircHandleStatsCommandsIndirect = ircHandleStatsCommands
  2392. }
  2393. func ircHandleStatsUptime(c *client) {
  2394. uptime := time.Now().Sub(started) / time.Second
  2395. days := uptime / 60 / 60 / 24
  2396. hours := (uptime % (60 * 60 * 24)) / 60 / 60
  2397. mins := (uptime % (60 * 60)) / 60
  2398. secs := uptime % 60
  2399. c.sendReply(RPL_STATSUPTIME, days, hours, mins, secs)
  2400. }
  2401. func ircHandleSTATS(msg *message, c *client) {
  2402. var query byte
  2403. if len(msg.params) > 0 && len(msg.params[0]) > 0 {
  2404. query = msg.params[0][0]
  2405. }
  2406. if len(msg.params) > 1 && !ircIsThisMe(msg.params[1]) {
  2407. c.sendReply(ERR_NOSUCHSERVER, msg.params[0])
  2408. return
  2409. }
  2410. if 0 == c.mode&ircUserModeOperator {
  2411. c.sendReply(ERR_NOPRIVILEGES)
  2412. return
  2413. }
  2414. switch query {
  2415. case 'L':
  2416. ircHandleStatsLinks(c, msg)
  2417. case 'm':
  2418. ircHandleStatsCommandsIndirect(c)
  2419. case 'u':
  2420. ircHandleStatsUptime(c)
  2421. }
  2422. c.sendReply(RPL_ENDOFSTATS, query)
  2423. }
  2424. func ircHandleLINKS(msg *message, c *client) {
  2425. if len(msg.params) > 1 && !ircIsThisMe(msg.params[0]) {
  2426. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2427. return
  2428. }
  2429. mask := "*"
  2430. if len(msg.params) > 0 {
  2431. if len(msg.params) > 1 {
  2432. mask = msg.params[1]
  2433. } else {
  2434. mask = msg.params[0]
  2435. }
  2436. }
  2437. if ircFnmatch(mask, serverName) {
  2438. c.sendReply(RPL_LINKS, mask, serverName,
  2439. 0 /* hop count */, config["server_info"])
  2440. }
  2441. c.sendReply(RPL_ENDOFLINKS, mask)
  2442. }
  2443. func ircHandleKILL(msg *message, c *client) {
  2444. if len(msg.params) < 2 {
  2445. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2446. return
  2447. }
  2448. if 0 == c.mode&ircUserModeOperator {
  2449. c.sendReply(ERR_NOPRIVILEGES)
  2450. return
  2451. }
  2452. target := users[ircToCanon(msg.params[0])]
  2453. if target == nil {
  2454. c.sendReply(ERR_NOSUCHNICK, msg.params[0])
  2455. return
  2456. }
  2457. c.sendf(":%s!%s@%s KILL %s :%s",
  2458. c.nickname, c.username, c.hostname, target.nickname, msg.params[1])
  2459. target.closeLink(fmt.Sprintf("Killed by %s: %s", c.nickname, msg.params[1]))
  2460. }
  2461. func ircHandleDIE(msg *message, c *client) {
  2462. if 0 == c.mode&ircUserModeOperator {
  2463. c.sendReply(ERR_NOPRIVILEGES)
  2464. } else if !quitting {
  2465. initiateQuit()
  2466. }
  2467. }
  2468. // -----------------------------------------------------------------------------
  2469. // TODO: Add an index for ERR_NOSUCHSERVER validation?
  2470. // TODO: Add a minimal parameter count?
  2471. // TODO: Add a field for oper-only commands? Use flags?
  2472. var ircHandlers = map[string]*ircCommand{
  2473. "CAP": {false, ircHandleCAP, 0, 0},
  2474. "PASS": {false, ircHandlePASS, 0, 0},
  2475. "NICK": {false, ircHandleNICK, 0, 0},
  2476. "USER": {false, ircHandleUSER, 0, 0},
  2477. "USERHOST": {true, ircHandleUSERHOST, 0, 0},
  2478. "LUSERS": {true, ircHandleLUSERS, 0, 0},
  2479. "MOTD": {true, ircHandleMOTD, 0, 0},
  2480. "PING": {true, ircHandlePING, 0, 0},
  2481. "PONG": {false, ircHandlePONG, 0, 0},
  2482. "QUIT": {false, ircHandleQUIT, 0, 0},
  2483. "TIME": {true, ircHandleTIME, 0, 0},
  2484. "VERSION": {true, ircHandleVERSION, 0, 0},
  2485. "USERS": {true, ircHandleUSERS, 0, 0},
  2486. "SUMMON": {true, ircHandleSUMMON, 0, 0},
  2487. "AWAY": {true, ircHandleAWAY, 0, 0},
  2488. "ADMIN": {true, ircHandleADMIN, 0, 0},
  2489. "STATS": {true, ircHandleSTATS, 0, 0},
  2490. "LINKS": {true, ircHandleLINKS, 0, 0},
  2491. "MODE": {true, ircHandleMODE, 0, 0},
  2492. "PRIVMSG": {true, ircHandlePRIVMSG, 0, 0},
  2493. "NOTICE": {true, ircHandleNOTICE, 0, 0},
  2494. "JOIN": {true, ircHandleJOIN, 0, 0},
  2495. "PART": {true, ircHandlePART, 0, 0},
  2496. "KICK": {true, ircHandleKICK, 0, 0},
  2497. "INVITE": {true, ircHandleINVITE, 0, 0},
  2498. "TOPIC": {true, ircHandleTOPIC, 0, 0},
  2499. "LIST": {true, ircHandleLIST, 0, 0},
  2500. "NAMES": {true, ircHandleNAMES, 0, 0},
  2501. "WHO": {true, ircHandleWHO, 0, 0},
  2502. "WHOIS": {true, ircHandleWHOIS, 0, 0},
  2503. "WHOWAS": {true, ircHandleWHOWAS, 0, 0},
  2504. "ISON": {true, ircHandleISON, 0, 0},
  2505. "KILL": {true, ircHandleKILL, 0, 0},
  2506. "DIE": {true, ircHandleDIE, 0, 0},
  2507. }
  2508. func ircProcessMessage(c *client, msg *message, raw string) {
  2509. if c.closing {
  2510. return
  2511. }
  2512. c.nReceivedMessages++
  2513. c.receivedBytes += len(raw) + 2
  2514. if !c.antiflood.check() {
  2515. c.closeLink("Excess flood")
  2516. return
  2517. }
  2518. if cmd, ok := ircHandlers[ircToCanon(msg.command)]; !ok {
  2519. c.sendReply(ERR_UNKNOWNCOMMAND, msg.command)
  2520. } else {
  2521. cmd.nReceived++
  2522. cmd.bytesReceived += len(raw) + 2
  2523. if cmd.requiresRegistration && !c.registered {
  2524. c.sendReply(ERR_NOTREGISTERED)
  2525. } else {
  2526. cmd.handler(msg, c)
  2527. }
  2528. }
  2529. }
  2530. // --- Network I/O -------------------------------------------------------------
  2531. // Handle the results from initializing the client's connection.
  2532. func (c *client) onPrepared(host string, isTLS bool) {
  2533. c.printDebug("client resolved to %s, TLS %t", host, isTLS)
  2534. if !isTLS {
  2535. c.conn = c.transport.(connCloseWriter)
  2536. } else if tlsConf != nil {
  2537. c.tls = tls.Server(c.transport, tlsConf)
  2538. c.conn = c.tls
  2539. } else {
  2540. c.printDebug("could not initialize TLS: disabled")
  2541. c.kill("TLS support disabled")
  2542. return
  2543. }
  2544. c.hostname = host
  2545. c.address = net.JoinHostPort(host, c.port)
  2546. // If we tried to send any data before now, we would need to flushSendQ.
  2547. go read(c)
  2548. c.reading = true
  2549. c.setPingTimer()
  2550. }
  2551. // Handle the results from trying to read from the client connection.
  2552. func (c *client) onRead(data []byte, readErr error) {
  2553. if !c.reading {
  2554. // Abusing the flag to emulate CloseRead and skip over data, see below.
  2555. return
  2556. }
  2557. c.recvQ = append(c.recvQ, data...)
  2558. for {
  2559. // XXX: This accepts even simple LF newlines, even though they're not
  2560. // really allowed by the protocol.
  2561. advance, token, _ := bufio.ScanLines(c.recvQ, false /* atEOF */)
  2562. if advance == 0 {
  2563. break
  2564. }
  2565. // XXX: And since it accepts LF, we miscalculate receivedBytes within.
  2566. c.recvQ = c.recvQ[advance:]
  2567. line := string(token)
  2568. c.printDebug("-> %s", line)
  2569. if msg := ircParseMessage(line); msg == nil {
  2570. c.printDebug("error: invalid line")
  2571. } else {
  2572. ircProcessMessage(c, msg, line)
  2573. }
  2574. }
  2575. if readErr != nil {
  2576. c.reading = false
  2577. if readErr != io.EOF {
  2578. c.printDebug("%s", readErr)
  2579. c.kill(readErr.Error())
  2580. } else if c.closing {
  2581. // Disregarding whether a clean shutdown has happened or not.
  2582. c.printDebug("client finished shutdown")
  2583. c.kill("")
  2584. } else {
  2585. c.printDebug("client EOF")
  2586. c.closeLink("")
  2587. }
  2588. } else if len(c.recvQ) > 8192 {
  2589. c.closeLink("recvQ overrun")
  2590. // tls.Conn doesn't have the CloseRead method (and it needs to be able
  2591. // to read from the TCP connection even for writes, so there isn't much
  2592. // sense in expecting the implementation to do anything useful),
  2593. // otherwise we'd use it to block incoming packet data.
  2594. c.reading = false
  2595. }
  2596. }
  2597. // Spawn a goroutine to flush the sendQ if possible and necessary.
  2598. func (c *client) flushSendQ() {
  2599. if !c.writing && c.conn != nil {
  2600. go write(c, c.sendQ)
  2601. c.writing = true
  2602. }
  2603. }
  2604. // Handle the results from trying to write to the client connection.
  2605. func (c *client) onWrite(written int, writeErr error) {
  2606. c.sendQ = c.sendQ[written:]
  2607. c.writing = false
  2608. if writeErr != nil {
  2609. c.printDebug("%s", writeErr)
  2610. c.kill(writeErr.Error())
  2611. } else if len(c.sendQ) > 0 {
  2612. c.flushSendQ()
  2613. } else if c.closing {
  2614. if c.reading {
  2615. c.conn.CloseWrite()
  2616. } else {
  2617. c.kill("")
  2618. }
  2619. }
  2620. }
  2621. // --- Worker goroutines -------------------------------------------------------
  2622. func accept(ln net.Listener) {
  2623. for {
  2624. // Error handling here may be tricky, see go #6163, #24808.
  2625. if conn, err := ln.Accept(); err != nil {
  2626. // See go #4373, they're being dicks. Another solution would be to
  2627. // pass a done channel to this function and close it before closing
  2628. // all the listeners, returning from here if it's readable.
  2629. if strings.Contains(err.Error(),
  2630. "use of closed network connection") {
  2631. return
  2632. }
  2633. if op, ok := err.(net.Error); !ok || !op.Temporary() {
  2634. exitFatal("%s", err)
  2635. } else {
  2636. printError("%s", err)
  2637. }
  2638. } else {
  2639. // TCP_NODELAY is set by default on TCPConns.
  2640. conns <- conn
  2641. }
  2642. }
  2643. }
  2644. func prepare(client *client) {
  2645. conn, host := client.transport, client.hostname
  2646. // The Cgo resolver doesn't pthread_cancel getnameinfo threads, so not
  2647. // bothering with pointless contexts.
  2648. ch := make(chan string, 1)
  2649. go func() {
  2650. defer close(ch)
  2651. if names, err := net.LookupAddr(host); err != nil {
  2652. printError("%s", err)
  2653. } else {
  2654. ch <- names[0]
  2655. }
  2656. }()
  2657. // While we can't cancel it, we still want to set a timeout on it.
  2658. select {
  2659. case <-time.After(5 * time.Second):
  2660. case resolved, ok := <-ch:
  2661. if ok {
  2662. host = resolved
  2663. }
  2664. }
  2665. // Note that in this demo application the autodetection prevents non-TLS
  2666. // clients from receiving any messages until they send something.
  2667. isTLS := false
  2668. if sysconn, err := conn.(syscall.Conn).SyscallConn(); err != nil {
  2669. // This is just for the TLS detection and doesn't need to be fatal.
  2670. printError("%s", err)
  2671. } else {
  2672. isTLS = detectTLS(sysconn)
  2673. }
  2674. prepared <- preparedEvent{client, host, isTLS}
  2675. }
  2676. func read(client *client) {
  2677. // A new buffer is allocated each time we receive some bytes, because of
  2678. // thread-safety. Therefore the buffer shouldn't be too large, or we'd
  2679. // need to copy it each time into a precisely sized new buffer.
  2680. var err error
  2681. for err == nil {
  2682. var (
  2683. buf [512]byte
  2684. n int
  2685. )
  2686. n, err = client.conn.Read(buf[:])
  2687. reads <- readEvent{client, buf[:n], err}
  2688. }
  2689. }
  2690. // Flush sendQ, which is passed by parameter so that there are no data races.
  2691. func write(client *client, data []byte) {
  2692. // We just write as much as we can, the main goroutine does the looping.
  2693. n, err := client.conn.Write(data)
  2694. writes <- writeEvent{client, n, err}
  2695. }
  2696. // --- Event loop --------------------------------------------------------------
  2697. func processOneEvent() {
  2698. select {
  2699. case <-sigs:
  2700. if quitting {
  2701. forceQuit("requested by user")
  2702. } else {
  2703. initiateQuit()
  2704. }
  2705. case <-quitTimer:
  2706. forceQuit("timeout")
  2707. case callback := <-timers:
  2708. callback()
  2709. case conn := <-conns:
  2710. if maxConnections > 0 && len(clients) >= maxConnections {
  2711. printDebug("connection limit reached, refusing connection")
  2712. conn.Close()
  2713. break
  2714. }
  2715. address := conn.RemoteAddr().String()
  2716. host, port, err := net.SplitHostPort(address)
  2717. if err != nil {
  2718. // In effect, we require TCP/UDP, as they have port numbers.
  2719. exitFatal("%s", err)
  2720. }
  2721. c := &client{
  2722. transport: conn,
  2723. address: address,
  2724. hostname: host,
  2725. port: port,
  2726. capVersion: 301,
  2727. opened: time.Now(),
  2728. lastActive: time.Now(),
  2729. // TODO: Make this configurable and more fine-grained.
  2730. antiflood: newFloodDetector(10*time.Second, 20),
  2731. }
  2732. clients[c] = true
  2733. c.printDebug("new client")
  2734. go prepare(c)
  2735. // The TLS autodetection in prepare needs to have a timeout.
  2736. c.setKillTimer()
  2737. case ev := <-prepared:
  2738. if _, ok := clients[ev.client]; ok {
  2739. ev.client.onPrepared(ev.host, ev.isTLS)
  2740. }
  2741. case ev := <-reads:
  2742. if _, ok := clients[ev.client]; ok {
  2743. ev.client.onRead(ev.data, ev.err)
  2744. }
  2745. case ev := <-writes:
  2746. if _, ok := clients[ev.client]; ok {
  2747. ev.client.onWrite(ev.written, ev.err)
  2748. }
  2749. }
  2750. }
  2751. // --- Application setup -------------------------------------------------------
  2752. func ircInitializeTLS() error {
  2753. configCert, configKey := config["tls_cert"], config["tls_key"]
  2754. // Only try to enable SSL support if the user configures it; it is not
  2755. // a failure if no one has requested it.
  2756. if configCert == "" && configKey == "" {
  2757. return nil
  2758. } else if configCert == "" {
  2759. return errors.New("no TLS certificate set")
  2760. } else if configKey == "" {
  2761. return errors.New("no TLS private key set")
  2762. }
  2763. pathCert := resolveFilename(configCert, resolveRelativeConfigFilename)
  2764. if pathCert == "" {
  2765. return fmt.Errorf("cannot find file: %s", configCert)
  2766. }
  2767. pathKey := resolveFilename(configKey, resolveRelativeConfigFilename)
  2768. if pathKey == "" {
  2769. return fmt.Errorf("cannot find file: %s", configKey)
  2770. }
  2771. cert, err := tls.LoadX509KeyPair(pathCert, pathKey)
  2772. if err != nil {
  2773. return err
  2774. }
  2775. tlsConf = &tls.Config{
  2776. Certificates: []tls.Certificate{cert},
  2777. ClientAuth: tls.RequestClientCert,
  2778. SessionTicketsDisabled: true,
  2779. }
  2780. return nil
  2781. }
  2782. func ircInitializeCatalog() error {
  2783. configCatalog := config["catalog"]
  2784. if configCatalog == "" {
  2785. return nil
  2786. }
  2787. path := resolveFilename(configCatalog, resolveRelativeConfigFilename)
  2788. if path == "" {
  2789. return fmt.Errorf("cannot find file: %s", configCatalog)
  2790. }
  2791. f, err := os.Open(path)
  2792. if err != nil {
  2793. return fmt.Errorf("failed reading the MOTD file: %s", err)
  2794. }
  2795. defer f.Close()
  2796. scanner := bufio.NewScanner(f)
  2797. catalog = make(map[int]string)
  2798. for lineNo := 1; scanner.Scan(); lineNo++ {
  2799. line := strings.TrimLeft(scanner.Text(), " \t")
  2800. if line == "" || strings.HasPrefix(line, "#") {
  2801. continue
  2802. }
  2803. delim := strings.IndexAny(line, " \t")
  2804. if delim < 0 {
  2805. return fmt.Errorf("%s:%d: malformed line", path, lineNo)
  2806. }
  2807. id, err := strconv.ParseUint(line[:delim], 10, 16)
  2808. if err != nil {
  2809. return fmt.Errorf("%s:%d: %s", path, lineNo, err)
  2810. }
  2811. catalog[int(id)] = line[delim+1:]
  2812. }
  2813. return scanner.Err()
  2814. }
  2815. func ircInitializeMOTD() error {
  2816. configMOTD := config["motd"]
  2817. if configMOTD == "" {
  2818. return nil
  2819. }
  2820. path := resolveFilename(configMOTD, resolveRelativeConfigFilename)
  2821. if path == "" {
  2822. return fmt.Errorf("cannot find file: %s", configMOTD)
  2823. }
  2824. f, err := os.Open(path)
  2825. if err != nil {
  2826. return fmt.Errorf("failed reading the MOTD file: %s", err)
  2827. }
  2828. defer f.Close()
  2829. scanner := bufio.NewScanner(f)
  2830. motd = nil
  2831. for scanner.Scan() {
  2832. motd = append(motd, scanner.Text())
  2833. }
  2834. return scanner.Err()
  2835. }
  2836. type configProcessor struct {
  2837. err error // any error that has occurred so far
  2838. }
  2839. func (cp *configProcessor) read(name string, process func(string) string) {
  2840. if cp.err != nil {
  2841. return
  2842. }
  2843. if err := process(config[name]); err != "" {
  2844. cp.err = fmt.Errorf("invalid configuration value for `%s': %s",
  2845. name, err)
  2846. }
  2847. }
  2848. // This function handles values that require validation before their first use,
  2849. // or some kind of a transformation (such as conversion to an integer) needs
  2850. // to be done before they can be used directly.
  2851. func ircParseConfig() error {
  2852. cp := &configProcessor{}
  2853. cp.read("ping_interval", func(value string) string {
  2854. if u, err := strconv.ParseUint(
  2855. config["ping_interval"], 10, 32); err != nil {
  2856. return err.Error()
  2857. } else if u < 1 {
  2858. return "the value is out of range"
  2859. } else {
  2860. pingInterval = time.Second * time.Duration(u)
  2861. }
  2862. return ""
  2863. })
  2864. cp.read("max_connections", func(value string) string {
  2865. if i, err := strconv.ParseInt(
  2866. value, 10, 32); err != nil {
  2867. return err.Error()
  2868. } else if i < 0 {
  2869. return "the value is out of range"
  2870. } else {
  2871. maxConnections = int(i)
  2872. }
  2873. return ""
  2874. })
  2875. cp.read("operators", func(value string) string {
  2876. operators = make(map[string]bool)
  2877. for _, fp := range splitString(value, ",", true) {
  2878. if !ircIsValidFingerprint(fp) {
  2879. return "invalid fingerprint value"
  2880. }
  2881. operators[strings.ToLower(fp)] = true
  2882. }
  2883. return ""
  2884. })
  2885. return cp.err
  2886. }
  2887. func ircInitializeServerName() error {
  2888. if value := config["server_name"]; value != "" {
  2889. if err := ircValidateHostname(value); err != nil {
  2890. return err
  2891. }
  2892. serverName = value
  2893. return nil
  2894. }
  2895. if hostname, err := os.Hostname(); err != nil {
  2896. return err
  2897. } else if err := ircValidateHostname(hostname); err != nil {
  2898. return err
  2899. } else {
  2900. serverName = hostname
  2901. }
  2902. return nil
  2903. }
  2904. func ircSetupListenFDs() error {
  2905. for _, address := range splitString(config["bind"], ",", true) {
  2906. ln, err := net.Listen("tcp", address)
  2907. if err != nil {
  2908. return err
  2909. }
  2910. listeners = append(listeners, ln)
  2911. printStatus("listening on %s", address)
  2912. }
  2913. if len(listeners) == 0 {
  2914. return errors.New("network setup failed: no ports to listen on")
  2915. }
  2916. for _, ln := range listeners {
  2917. go accept(ln)
  2918. }
  2919. return nil
  2920. }
  2921. // --- Main --------------------------------------------------------------------
  2922. func main() {
  2923. flag.BoolVar(&debugMode, "debug", false, "run in verbose debug mode")
  2924. version := flag.Bool("version", false, "show version and exit")
  2925. writeDefaultCfg := flag.Bool("writedefaultcfg", false,
  2926. "write a default configuration file and exit")
  2927. systemd := flag.Bool("systemd", false, "log in systemd format")
  2928. flag.Parse()
  2929. if *version {
  2930. fmt.Printf("%s %s\n", projectName, projectVersion)
  2931. return
  2932. }
  2933. if *writeDefaultCfg {
  2934. callSimpleConfigWriteDefault("", configTable)
  2935. return
  2936. }
  2937. if *systemd {
  2938. logMessage = logMessageSystemd
  2939. }
  2940. if flag.NArg() > 0 {
  2941. flag.Usage()
  2942. os.Exit(2)
  2943. }
  2944. config = make(simpleConfig)
  2945. config.loadDefaults(configTable)
  2946. if err := config.updateFromFile(); err != nil && !os.IsNotExist(err) {
  2947. printError("error loading configuration: %s", err)
  2948. os.Exit(1)
  2949. }
  2950. started = time.Now()
  2951. signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
  2952. for _, fn := range []func() error{
  2953. ircInitializeTLS,
  2954. ircInitializeServerName,
  2955. ircInitializeMOTD,
  2956. ircInitializeCatalog,
  2957. ircParseConfig,
  2958. ircSetupListenFDs,
  2959. } {
  2960. if err := fn(); err != nil {
  2961. exitFatal("%s", err)
  2962. }
  2963. }
  2964. for !quitting || len(clients) > 0 {
  2965. processOneEvent()
  2966. }
  2967. }