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.

client.go 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. // Copyright (c) 2012-2014 Jeremy Latt
  2. // Copyright (c) 2014-2015 Edmund Huber
  3. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  4. // released under the MIT license
  5. package irc
  6. import (
  7. "errors"
  8. "fmt"
  9. "log"
  10. "net"
  11. "runtime/debug"
  12. "strconv"
  13. "strings"
  14. "sync"
  15. "sync/atomic"
  16. "time"
  17. "github.com/goshuirc/irc-go/ircfmt"
  18. "github.com/goshuirc/irc-go/ircmsg"
  19. ident "github.com/oragono/go-ident"
  20. "github.com/oragono/oragono/irc/caps"
  21. "github.com/oragono/oragono/irc/sno"
  22. "github.com/oragono/oragono/irc/utils"
  23. )
  24. const (
  25. // IdentTimeoutSeconds is how many seconds before our ident (username) check times out.
  26. IdentTimeoutSeconds = 1.5
  27. )
  28. var (
  29. // ErrNickAlreadySet is a weird error that's sent when the server's consistency has been compromised.
  30. ErrNickAlreadySet = errors.New("Nickname is already set")
  31. )
  32. // Client is an IRC client.
  33. type Client struct {
  34. account *ClientAccount
  35. atime time.Time
  36. authorized bool
  37. awayMessage string
  38. capabilities *caps.Set
  39. capState CapState
  40. capVersion caps.Version
  41. certfp string
  42. channels ChannelSet
  43. class *OperClass
  44. ctime time.Time
  45. exitedSnomaskSent bool
  46. flags map[Mode]bool
  47. hasQuit bool
  48. hops int
  49. hostname string
  50. idletimer *IdleTimer
  51. isDestroyed bool
  52. isQuitting bool
  53. maxlenTags uint32
  54. maxlenRest uint32
  55. nick string
  56. nickCasefolded string
  57. nickMaskCasefolded string
  58. nickMaskString string // cache for nickmask string since it's used with lots of replies
  59. operName string
  60. proxiedIP string // actual remote IP if using the PROXY protocol
  61. quitMessage string
  62. rawHostname string
  63. realname string
  64. registered bool
  65. saslInProgress bool
  66. saslMechanism string
  67. saslValue string
  68. server *Server
  69. socket *Socket
  70. stateMutex sync.RWMutex // tier 1
  71. username string
  72. vhost string
  73. whoisLine string
  74. }
  75. // NewClient returns a client with all the appropriate info setup.
  76. func NewClient(server *Server, conn net.Conn, isTLS bool) *Client {
  77. now := time.Now()
  78. socket := NewSocket(conn, server.MaxSendQBytes)
  79. go socket.RunSocketWriter()
  80. client := &Client{
  81. atime: now,
  82. authorized: server.Password() == nil,
  83. capabilities: caps.NewSet(),
  84. capState: CapNone,
  85. capVersion: caps.Cap301,
  86. channels: make(ChannelSet),
  87. ctime: now,
  88. flags: make(map[Mode]bool),
  89. server: server,
  90. socket: &socket,
  91. account: &NoAccount,
  92. nick: "*", // * is used until actual nick is given
  93. nickCasefolded: "*",
  94. nickMaskString: "*", // * is used until actual nick is given
  95. }
  96. client.recomputeMaxlens()
  97. if isTLS {
  98. client.flags[TLS] = true
  99. // error is not useful to us here anyways so we can ignore it
  100. client.certfp, _ = client.socket.CertFP()
  101. }
  102. if server.checkIdent {
  103. _, serverPortString, err := net.SplitHostPort(conn.LocalAddr().String())
  104. serverPort, _ := strconv.Atoi(serverPortString)
  105. if err != nil {
  106. log.Fatal(err)
  107. }
  108. clientHost, clientPortString, err := net.SplitHostPort(conn.RemoteAddr().String())
  109. clientPort, _ := strconv.Atoi(clientPortString)
  110. if err != nil {
  111. log.Fatal(err)
  112. }
  113. client.Notice("*** Looking up your username")
  114. resp, err := ident.Query(clientHost, serverPort, clientPort, IdentTimeoutSeconds)
  115. if err == nil {
  116. username := resp.Identifier
  117. _, err := CasefoldName(username) // ensure it's a valid username
  118. if err == nil {
  119. client.Notice("*** Found your username")
  120. client.username = username
  121. // we don't need to updateNickMask here since nickMask is not used for anything yet
  122. } else {
  123. client.Notice("*** Got a malformed username, ignoring")
  124. }
  125. } else {
  126. client.Notice("*** Could not find your username")
  127. }
  128. }
  129. go client.run()
  130. return client
  131. }
  132. // IP returns the IP address of this client.
  133. func (client *Client) IP() net.IP {
  134. if client.proxiedIP != "" {
  135. return net.ParseIP(client.proxiedIP)
  136. }
  137. return net.ParseIP(utils.IPString(client.socket.conn.RemoteAddr()))
  138. }
  139. // IPString returns the IP address of this client as a string.
  140. func (client *Client) IPString() string {
  141. if client.proxiedIP != "" {
  142. return client.proxiedIP
  143. }
  144. ip := client.IP().String()
  145. if 0 < len(ip) && ip[0] == ':' {
  146. ip = "0" + ip
  147. }
  148. return ip
  149. }
  150. //
  151. // command goroutine
  152. //
  153. func (client *Client) recomputeMaxlens() (int, int) {
  154. maxlenTags := 512
  155. maxlenRest := 512
  156. if client.capabilities.Has(caps.MessageTags) {
  157. maxlenTags = 4096
  158. }
  159. if client.capabilities.Has(caps.MaxLine) {
  160. limits := client.server.Limits()
  161. if limits.LineLen.Tags > maxlenTags {
  162. maxlenTags = limits.LineLen.Tags
  163. }
  164. maxlenRest = limits.LineLen.Rest
  165. }
  166. atomic.StoreUint32(&client.maxlenTags, uint32(maxlenTags))
  167. atomic.StoreUint32(&client.maxlenRest, uint32(maxlenRest))
  168. return maxlenTags, maxlenRest
  169. }
  170. // allow these negotiated length limits to be read without locks; this is a convenience
  171. // so that Client.Send doesn't have to acquire any Client locks
  172. func (client *Client) maxlens() (int, int) {
  173. return int(atomic.LoadUint32(&client.maxlenTags)), int(atomic.LoadUint32(&client.maxlenRest))
  174. }
  175. func (client *Client) run() {
  176. var err error
  177. var isExiting bool
  178. var line string
  179. var msg ircmsg.IrcMessage
  180. defer func() {
  181. if r := recover(); r != nil {
  182. client.server.logger.Error("internal",
  183. fmt.Sprintf("Client caused panic: %v\n%s", r, debug.Stack()))
  184. if client.server.RecoverFromErrors() {
  185. client.server.logger.Error("internal", "Disconnecting client and attempting to recover")
  186. } else {
  187. panic(r)
  188. }
  189. }
  190. // ensure client connection gets closed
  191. client.destroy()
  192. }()
  193. client.idletimer = NewIdleTimer(client)
  194. client.idletimer.Start()
  195. // Set the hostname for this client
  196. // (may be overridden by a later PROXY command from stunnel)
  197. client.rawHostname = utils.AddrLookupHostname(client.socket.conn.RemoteAddr())
  198. for {
  199. maxlenTags, maxlenRest := client.recomputeMaxlens()
  200. line, err = client.socket.Read()
  201. if err != nil {
  202. client.Quit("connection closed")
  203. break
  204. }
  205. client.server.logger.Debug("userinput ", client.nick, "<- ", line)
  206. msg, err = ircmsg.ParseLineMaxLen(line, maxlenTags, maxlenRest)
  207. if err == ircmsg.ErrorLineIsEmpty {
  208. continue
  209. } else if err != nil {
  210. client.Quit("received malformed line")
  211. break
  212. }
  213. cmd, exists := Commands[msg.Command]
  214. if !exists {
  215. if len(msg.Command) > 0 {
  216. client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.nick, msg.Command, "Unknown command")
  217. } else {
  218. client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.nick, "lastcmd", "No command given")
  219. }
  220. continue
  221. }
  222. isExiting = cmd.Run(client.server, client, msg)
  223. if isExiting || client.isQuitting {
  224. break
  225. }
  226. }
  227. }
  228. //
  229. // idle, quit, timers and timeouts
  230. //
  231. // Active updates when the client was last 'active' (i.e. the user should be sitting in front of their client).
  232. func (client *Client) Active() {
  233. client.atime = time.Now()
  234. }
  235. // Touch marks the client as alive (as it it has a connection to us and we
  236. // can receive messages from it).
  237. func (client *Client) Touch() {
  238. client.idletimer.Touch()
  239. }
  240. // Ping sends the client a PING message.
  241. func (client *Client) Ping() {
  242. client.Send(nil, "", "PING", client.nick)
  243. }
  244. //
  245. // server goroutine
  246. //
  247. // Register sets the client details as appropriate when entering the network.
  248. func (client *Client) Register() {
  249. client.stateMutex.Lock()
  250. alreadyRegistered := client.registered
  251. client.registered = true
  252. client.stateMutex.Unlock()
  253. if alreadyRegistered {
  254. return
  255. }
  256. client.Touch()
  257. client.updateNickMask("")
  258. client.server.monitorManager.AlertAbout(client, true)
  259. }
  260. // IdleTime returns how long this client's been idle.
  261. func (client *Client) IdleTime() time.Duration {
  262. return time.Since(client.atime)
  263. }
  264. // SignonTime returns this client's signon time as a unix timestamp.
  265. func (client *Client) SignonTime() int64 {
  266. return client.ctime.Unix()
  267. }
  268. // IdleSeconds returns the number of seconds this client's been idle.
  269. func (client *Client) IdleSeconds() uint64 {
  270. return uint64(client.IdleTime().Seconds())
  271. }
  272. // HasNick returns true if the client's nickname is set (used in registration).
  273. func (client *Client) HasNick() bool {
  274. client.stateMutex.RLock()
  275. defer client.stateMutex.RUnlock()
  276. return client.nick != "" && client.nick != "*"
  277. }
  278. // HasUsername returns true if the client's username is set (used in registration).
  279. func (client *Client) HasUsername() bool {
  280. client.stateMutex.RLock()
  281. defer client.stateMutex.RUnlock()
  282. return client.username != "" && client.username != "*"
  283. }
  284. // HasRoleCapabs returns true if client has the given (role) capabilities.
  285. func (client *Client) HasRoleCapabs(capabs ...string) bool {
  286. if client.class == nil {
  287. return false
  288. }
  289. for _, capab := range capabs {
  290. if !client.class.Capabilities[capab] {
  291. return false
  292. }
  293. }
  294. return true
  295. }
  296. // ModeString returns the mode string for this client.
  297. func (client *Client) ModeString() (str string) {
  298. str = "+"
  299. for flag := range client.flags {
  300. str += flag.String()
  301. }
  302. return
  303. }
  304. // Friends refers to clients that share a channel with this client.
  305. func (client *Client) Friends(capabs ...caps.Capability) ClientSet {
  306. friends := make(ClientSet)
  307. // make sure that I have the right caps
  308. hasCaps := true
  309. for _, capab := range capabs {
  310. if !client.capabilities.Has(capab) {
  311. hasCaps = false
  312. break
  313. }
  314. }
  315. if hasCaps {
  316. friends.Add(client)
  317. }
  318. for _, channel := range client.Channels() {
  319. for _, member := range channel.Members() {
  320. // make sure they have all the required caps
  321. hasCaps = true
  322. for _, capab := range capabs {
  323. if !member.capabilities.Has(capab) {
  324. hasCaps = false
  325. break
  326. }
  327. }
  328. if hasCaps {
  329. friends.Add(member)
  330. }
  331. }
  332. }
  333. return friends
  334. }
  335. // updateNick updates `nick` and `nickCasefolded`.
  336. func (client *Client) updateNick(nick string) {
  337. casefoldedName, err := CasefoldName(nick)
  338. if err != nil {
  339. log.Println(fmt.Sprintf("ERROR: Nick [%s] couldn't be casefolded... this should never happen. Printing stacktrace.", client.nick))
  340. debug.PrintStack()
  341. }
  342. client.stateMutex.Lock()
  343. client.nick = nick
  344. client.nickCasefolded = casefoldedName
  345. client.stateMutex.Unlock()
  346. }
  347. // updateNickMask updates the casefolded nickname and nickmask.
  348. func (client *Client) updateNickMask(nick string) {
  349. // on "", just regenerate the nickmask etc.
  350. // otherwise, update the actual nick
  351. if nick != "" {
  352. client.updateNick(nick)
  353. }
  354. client.stateMutex.Lock()
  355. defer client.stateMutex.Unlock()
  356. if len(client.vhost) > 0 {
  357. client.hostname = client.vhost
  358. } else {
  359. client.hostname = client.rawHostname
  360. }
  361. nickMaskString := fmt.Sprintf("%s!%s@%s", client.nick, client.username, client.hostname)
  362. nickMaskCasefolded, err := Casefold(nickMaskString)
  363. if err != nil {
  364. log.Println(fmt.Sprintf("ERROR: Nickmask [%s] couldn't be casefolded... this should never happen. Printing stacktrace.", client.nickMaskString))
  365. debug.PrintStack()
  366. }
  367. client.nickMaskString = nickMaskString
  368. client.nickMaskCasefolded = nickMaskCasefolded
  369. }
  370. // AllNickmasks returns all the possible nickmasks for the client.
  371. func (client *Client) AllNickmasks() []string {
  372. var masks []string
  373. var mask string
  374. var err error
  375. if len(client.vhost) > 0 {
  376. mask, err = Casefold(fmt.Sprintf("%s!%s@%s", client.nick, client.username, client.vhost))
  377. if err == nil {
  378. masks = append(masks, mask)
  379. }
  380. }
  381. mask, err = Casefold(fmt.Sprintf("%s!%s@%s", client.nick, client.username, client.rawHostname))
  382. if err == nil {
  383. masks = append(masks, mask)
  384. }
  385. mask2, err := Casefold(fmt.Sprintf("%s!%s@%s", client.nick, client.username, utils.IPString(client.socket.conn.RemoteAddr())))
  386. if err == nil && mask2 != mask {
  387. masks = append(masks, mask2)
  388. }
  389. return masks
  390. }
  391. // LoggedIntoAccount returns true if this client is logged into an account.
  392. func (client *Client) LoggedIntoAccount() bool {
  393. return client.account != nil && client.account != &NoAccount
  394. }
  395. // RplISupport outputs our ISUPPORT lines to the client. This is used on connection and in VERSION responses.
  396. func (client *Client) RplISupport() {
  397. for _, tokenline := range client.server.ISupport().CachedReply {
  398. // ugly trickery ahead
  399. client.Send(nil, client.server.name, RPL_ISUPPORT, append([]string{client.nick}, tokenline...)...)
  400. }
  401. }
  402. // Quit sets the given quit message for the client and tells the client to quit out.
  403. func (client *Client) Quit(message string) {
  404. client.stateMutex.Lock()
  405. alreadyQuit := client.isQuitting
  406. if !alreadyQuit {
  407. client.isQuitting = true
  408. client.quitMessage = message
  409. }
  410. client.stateMutex.Unlock()
  411. if alreadyQuit {
  412. return
  413. }
  414. quitMsg := ircmsg.MakeMessage(nil, client.nickMaskString, "QUIT", message)
  415. quitLine, _ := quitMsg.Line()
  416. errorMsg := ircmsg.MakeMessage(nil, "", "ERROR", message)
  417. errorLine, _ := errorMsg.Line()
  418. client.socket.SetFinalData(quitLine + errorLine)
  419. }
  420. // destroy gets rid of a client, removes them from server lists etc.
  421. func (client *Client) destroy() {
  422. // allow destroy() to execute at most once
  423. client.stateMutex.Lock()
  424. isDestroyed := client.isDestroyed
  425. client.isDestroyed = true
  426. client.stateMutex.Unlock()
  427. if isDestroyed {
  428. return
  429. }
  430. client.server.logger.Debug("quit", fmt.Sprintf("%s is no longer on the server", client.nick))
  431. // send quit/error message to client if they haven't been sent already
  432. client.Quit("Connection closed")
  433. client.server.whoWas.Append(client)
  434. friends := client.Friends()
  435. friends.Remove(client)
  436. // remove from connection limits
  437. ipaddr := client.IP()
  438. // this check shouldn't be required but eh
  439. if ipaddr != nil {
  440. client.server.connectionLimiter.RemoveClient(ipaddr)
  441. }
  442. // alert monitors
  443. client.server.monitorManager.AlertAbout(client, false)
  444. // clean up monitor state
  445. client.server.monitorManager.RemoveAll(client)
  446. // clean up channels
  447. for _, channel := range client.Channels() {
  448. channel.Quit(client)
  449. for _, member := range channel.Members() {
  450. friends.Add(member)
  451. }
  452. }
  453. // clean up server
  454. client.server.clients.Remove(client)
  455. // clean up self
  456. if client.idletimer != nil {
  457. client.idletimer.Stop()
  458. }
  459. client.socket.Close()
  460. // send quit messages to friends
  461. for friend := range friends {
  462. if client.quitMessage == "" {
  463. client.quitMessage = "Exited"
  464. }
  465. friend.Send(nil, client.nickMaskString, "QUIT", client.quitMessage)
  466. }
  467. if !client.exitedSnomaskSent {
  468. client.server.snomasks.Send(sno.LocalQuits, fmt.Sprintf(ircfmt.Unescape("%s$r exited the network"), client.nick))
  469. }
  470. }
  471. // SendSplitMsgFromClient sends an IRC PRIVMSG/NOTICE coming from a specific client.
  472. // Adds account-tag to the line as well.
  473. func (client *Client) SendSplitMsgFromClient(msgid string, from *Client, tags *map[string]ircmsg.TagValue, command, target string, message SplitMessage) {
  474. if client.capabilities.Has(caps.MaxLine) {
  475. client.SendFromClient(msgid, from, tags, command, target, message.ForMaxLine)
  476. } else {
  477. for _, str := range message.For512 {
  478. client.SendFromClient(msgid, from, tags, command, target, str)
  479. }
  480. }
  481. }
  482. // SendFromClient sends an IRC line coming from a specific client.
  483. // Adds account-tag to the line as well.
  484. func (client *Client) SendFromClient(msgid string, from *Client, tags *map[string]ircmsg.TagValue, command string, params ...string) error {
  485. // attach account-tag
  486. if client.capabilities.Has(caps.AccountTag) && from.account != &NoAccount {
  487. if tags == nil {
  488. tags = ircmsg.MakeTags("account", from.account.Name)
  489. } else {
  490. (*tags)["account"] = ircmsg.MakeTagValue(from.account.Name)
  491. }
  492. }
  493. // attach message-id
  494. if len(msgid) > 0 && client.capabilities.Has(caps.MessageTags) {
  495. if tags == nil {
  496. tags = ircmsg.MakeTags("draft/msgid", msgid)
  497. } else {
  498. (*tags)["draft/msgid"] = ircmsg.MakeTagValue(msgid)
  499. }
  500. }
  501. return client.Send(tags, from.nickMaskString, command, params...)
  502. }
  503. var (
  504. // these are all the output commands that MUST have their last param be a trailing.
  505. // this is needed because silly clients like to treat trailing as separate from the
  506. // other params in messages.
  507. commandsThatMustUseTrailing = map[string]bool{
  508. "PRIVMSG": true,
  509. "NOTICE": true,
  510. RPL_WHOISCHANNELS: true,
  511. RPL_USERHOST: true,
  512. }
  513. )
  514. // Send sends an IRC line to the client.
  515. func (client *Client) Send(tags *map[string]ircmsg.TagValue, prefix string, command string, params ...string) error {
  516. // attach server-time
  517. if client.capabilities.Has(caps.ServerTime) {
  518. t := time.Now().UTC().Format("2006-01-02T15:04:05.999Z")
  519. if tags == nil {
  520. tags = ircmsg.MakeTags("time", t)
  521. } else {
  522. (*tags)["time"] = ircmsg.MakeTagValue(t)
  523. }
  524. }
  525. // force trailing, if message requires it
  526. var usedTrailingHack bool
  527. if commandsThatMustUseTrailing[strings.ToUpper(command)] && len(params) > 0 {
  528. lastParam := params[len(params)-1]
  529. // to force trailing, we ensure the final param contains a space
  530. if !strings.Contains(lastParam, " ") {
  531. params[len(params)-1] = lastParam + " "
  532. usedTrailingHack = true
  533. }
  534. }
  535. // send out the message
  536. message := ircmsg.MakeMessage(tags, prefix, command, params...)
  537. maxlenTags, maxlenRest := client.maxlens()
  538. line, err := message.LineMaxLen(maxlenTags, maxlenRest)
  539. if err != nil {
  540. // try not to fail quietly - especially useful when running tests, as a note to dig deeper
  541. // log.Println("Error assembling message:")
  542. // spew.Dump(message)
  543. // debug.PrintStack()
  544. message = ircmsg.MakeMessage(nil, client.server.name, ERR_UNKNOWNERROR, "*", "Error assembling message for sending")
  545. line, _ := message.Line()
  546. client.socket.Write(line)
  547. return err
  548. }
  549. // is we used the trailing hack, we need to strip the final space we appended earlier
  550. if usedTrailingHack {
  551. line = line[:len(line)-3] + "\r\n"
  552. }
  553. client.server.logger.Debug("useroutput", client.nick, " ->", strings.TrimRight(line, "\r\n"))
  554. client.socket.Write(line)
  555. return nil
  556. }
  557. // Notice sends the client a notice from the server.
  558. func (client *Client) Notice(text string) {
  559. limit := 400
  560. if client.capabilities.Has(caps.MaxLine) {
  561. limit = client.server.Limits().LineLen.Rest - 110
  562. }
  563. lines := wordWrap(text, limit)
  564. for _, line := range lines {
  565. client.Send(nil, client.server.name, "NOTICE", client.nick, line)
  566. }
  567. }
  568. func (client *Client) addChannel(channel *Channel) {
  569. client.stateMutex.Lock()
  570. client.channels[channel] = true
  571. client.stateMutex.Unlock()
  572. }
  573. func (client *Client) removeChannel(channel *Channel) {
  574. client.stateMutex.Lock()
  575. delete(client.channels, channel)
  576. client.stateMutex.Unlock()
  577. }