Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

client.go 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119
  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. "fmt"
  8. "net"
  9. "runtime/debug"
  10. "strconv"
  11. "strings"
  12. "sync"
  13. "sync/atomic"
  14. "time"
  15. "github.com/goshuirc/irc-go/ircfmt"
  16. "github.com/goshuirc/irc-go/ircmsg"
  17. ident "github.com/oragono/go-ident"
  18. "github.com/oragono/oragono/irc/caps"
  19. "github.com/oragono/oragono/irc/connection_limits"
  20. "github.com/oragono/oragono/irc/history"
  21. "github.com/oragono/oragono/irc/modes"
  22. "github.com/oragono/oragono/irc/sno"
  23. "github.com/oragono/oragono/irc/utils"
  24. )
  25. const (
  26. // IdentTimeoutSeconds is how many seconds before our ident (username) check times out.
  27. IdentTimeoutSeconds = 1.5
  28. IRCv3TimestampFormat = "2006-01-02T15:04:05.000Z"
  29. )
  30. // ResumeDetails is a place to stash data at various stages of
  31. // the resume process: when handling the RESUME command itself,
  32. // when completing the registration, and when rejoining channels.
  33. type ResumeDetails struct {
  34. OldClient *Client
  35. PresentedToken string
  36. Timestamp time.Time
  37. ResumedAt time.Time
  38. Channels []string
  39. HistoryIncomplete bool
  40. }
  41. // Client is an IRC client.
  42. type Client struct {
  43. account string
  44. accountName string // display name of the account: uncasefolded, '*' if not logged in
  45. atime time.Time
  46. awayMessage string
  47. capabilities caps.Set
  48. capState caps.State
  49. capVersion caps.Version
  50. certfp string
  51. channels ChannelSet
  52. ctime time.Time
  53. exitedSnomaskSent bool
  54. fakelag Fakelag
  55. flags modes.ModeSet
  56. hasQuit bool
  57. hops int
  58. hostname string
  59. idletimer IdleTimer
  60. invitedTo map[string]bool
  61. isDestroyed bool
  62. isTor bool
  63. isQuitting bool
  64. languages []string
  65. loginThrottle connection_limits.GenericThrottle
  66. maxlenRest uint32
  67. nick string
  68. nickCasefolded string
  69. nickMaskCasefolded string
  70. nickMaskString string // cache for nickmask string since it's used with lots of replies
  71. nickTimer NickTimer
  72. oper *Oper
  73. preregNick string
  74. proxiedIP net.IP // actual remote IP if using the PROXY protocol
  75. quitMessage string
  76. rawHostname string
  77. realname string
  78. realIP net.IP
  79. registered bool
  80. resumeDetails *ResumeDetails
  81. resumeID string
  82. saslInProgress bool
  83. saslMechanism string
  84. saslValue string
  85. sentPassCommand bool
  86. server *Server
  87. skeleton string
  88. socket *Socket
  89. stateMutex sync.RWMutex // tier 1
  90. username string
  91. vhost string
  92. history *history.Buffer
  93. }
  94. // WhoWas is the subset of client details needed to answer a WHOWAS query
  95. type WhoWas struct {
  96. nick string
  97. nickCasefolded string
  98. username string
  99. hostname string
  100. realname string
  101. }
  102. // ClientDetails is a standard set of details about a client
  103. type ClientDetails struct {
  104. WhoWas
  105. nickMask string
  106. nickMaskCasefolded string
  107. account string
  108. accountName string
  109. }
  110. // NewClient sets up a new client and runs its goroutine.
  111. func RunNewClient(server *Server, conn clientConn) {
  112. now := time.Now()
  113. config := server.Config()
  114. fullLineLenLimit := ircmsg.MaxlenTagsFromClient + config.Limits.LineLen.Rest
  115. // give them 1k of grace over the limit:
  116. socket := NewSocket(conn.Conn, fullLineLenLimit+1024, config.Server.MaxSendQBytes)
  117. client := &Client{
  118. atime: now,
  119. capState: caps.NoneState,
  120. capVersion: caps.Cap301,
  121. channels: make(ChannelSet),
  122. ctime: now,
  123. isTor: conn.IsTor,
  124. languages: server.Languages().Default(),
  125. loginThrottle: connection_limits.GenericThrottle{
  126. Duration: config.Accounts.LoginThrottling.Duration,
  127. Limit: config.Accounts.LoginThrottling.MaxAttempts,
  128. },
  129. server: server,
  130. socket: socket,
  131. accountName: "*",
  132. nick: "*", // * is used until actual nick is given
  133. nickCasefolded: "*",
  134. nickMaskString: "*", // * is used until actual nick is given
  135. history: history.NewHistoryBuffer(config.History.ClientLength),
  136. }
  137. client.recomputeMaxlens()
  138. if conn.IsTLS {
  139. client.SetMode(modes.TLS, true)
  140. // error is not useful to us here anyways so we can ignore it
  141. client.certfp, _ = client.socket.CertFP()
  142. }
  143. if conn.IsTor {
  144. client.SetMode(modes.TLS, true)
  145. client.realIP = utils.IPv4LoopbackAddress
  146. client.rawHostname = config.Server.TorListeners.Vhost
  147. } else {
  148. remoteAddr := conn.Conn.RemoteAddr()
  149. client.realIP = utils.AddrToIP(remoteAddr)
  150. // Set the hostname for this client
  151. // (may be overridden by a later PROXY command from stunnel)
  152. client.rawHostname = utils.LookupHostname(client.realIP.String())
  153. if config.Server.CheckIdent && !utils.AddrIsUnix(remoteAddr) {
  154. client.doIdentLookup(conn.Conn)
  155. }
  156. }
  157. client.run()
  158. }
  159. func (client *Client) doIdentLookup(conn net.Conn) {
  160. _, serverPortString, err := net.SplitHostPort(conn.LocalAddr().String())
  161. if err != nil {
  162. client.server.logger.Error("internal", "bad server address", err.Error())
  163. return
  164. }
  165. serverPort, _ := strconv.Atoi(serverPortString)
  166. clientHost, clientPortString, err := net.SplitHostPort(conn.RemoteAddr().String())
  167. if err != nil {
  168. client.server.logger.Error("internal", "bad client address", err.Error())
  169. return
  170. }
  171. clientPort, _ := strconv.Atoi(clientPortString)
  172. client.Notice(client.t("*** Looking up your username"))
  173. resp, err := ident.Query(clientHost, serverPort, clientPort, IdentTimeoutSeconds)
  174. if err == nil {
  175. err := client.SetNames(resp.Identifier, "", true)
  176. if err == nil {
  177. client.Notice(client.t("*** Found your username"))
  178. // we don't need to updateNickMask here since nickMask is not used for anything yet
  179. } else {
  180. client.Notice(client.t("*** Got a malformed username, ignoring"))
  181. }
  182. } else {
  183. client.Notice(client.t("*** Could not find your username"))
  184. }
  185. }
  186. func (client *Client) isAuthorized(config *Config) bool {
  187. saslSent := client.account != ""
  188. // PASS requirement
  189. if (config.Server.passwordBytes != nil) && !client.sentPassCommand && !(config.Accounts.SkipServerPassword && saslSent) {
  190. return false
  191. }
  192. // Tor connections may be required to authenticate with SASL
  193. if client.isTor && config.Server.TorListeners.RequireSasl && !saslSent {
  194. return false
  195. }
  196. // finally, enforce require-sasl
  197. return !config.Accounts.RequireSasl.Enabled || saslSent || utils.IPInNets(client.IP(), config.Accounts.RequireSasl.exemptedNets)
  198. }
  199. func (client *Client) resetFakelag() {
  200. var flc FakelagConfig = client.server.Config().Fakelag
  201. flc.Enabled = flc.Enabled && !client.HasRoleCapabs("nofakelag")
  202. client.fakelag.Initialize(flc)
  203. }
  204. // IP returns the IP address of this client.
  205. func (client *Client) IP() net.IP {
  206. client.stateMutex.RLock()
  207. defer client.stateMutex.RUnlock()
  208. if client.proxiedIP != nil {
  209. return client.proxiedIP
  210. }
  211. return client.realIP
  212. }
  213. // IPString returns the IP address of this client as a string.
  214. func (client *Client) IPString() string {
  215. ip := client.IP().String()
  216. if 0 < len(ip) && ip[0] == ':' {
  217. ip = "0" + ip
  218. }
  219. return ip
  220. }
  221. //
  222. // command goroutine
  223. //
  224. func (client *Client) recomputeMaxlens() int {
  225. maxlenRest := 512
  226. if client.capabilities.Has(caps.MaxLine) {
  227. maxlenRest = client.server.Limits().LineLen.Rest
  228. }
  229. atomic.StoreUint32(&client.maxlenRest, uint32(maxlenRest))
  230. return maxlenRest
  231. }
  232. // allow these negotiated length limits to be read without locks; this is a convenience
  233. // so that Client.Send doesn't have to acquire any Client locks
  234. func (client *Client) MaxlenRest() int {
  235. return int(atomic.LoadUint32(&client.maxlenRest))
  236. }
  237. func (client *Client) run() {
  238. var err error
  239. var isExiting bool
  240. var line string
  241. var msg ircmsg.IrcMessage
  242. defer func() {
  243. if r := recover(); r != nil {
  244. client.server.logger.Error("internal",
  245. fmt.Sprintf("Client caused panic: %v\n%s", r, debug.Stack()))
  246. if client.server.RecoverFromErrors() {
  247. client.server.logger.Error("internal", "Disconnecting client and attempting to recover")
  248. } else {
  249. panic(r)
  250. }
  251. }
  252. // ensure client connection gets closed
  253. client.destroy(false)
  254. }()
  255. client.idletimer.Initialize(client)
  256. client.nickTimer.Initialize(client)
  257. client.resetFakelag()
  258. firstLine := true
  259. for {
  260. maxlenRest := client.recomputeMaxlens()
  261. line, err = client.socket.Read()
  262. if err != nil {
  263. quitMessage := "connection closed"
  264. if err == errReadQ {
  265. quitMessage = "readQ exceeded"
  266. }
  267. client.Quit(quitMessage)
  268. break
  269. }
  270. if client.server.logger.IsLoggingRawIO() {
  271. client.server.logger.Debug("userinput", client.nick, "<- ", line)
  272. }
  273. // special-cased handling of PROXY protocol, see `handleProxyCommand` for details:
  274. if firstLine {
  275. firstLine = false
  276. if strings.HasPrefix(line, "PROXY") {
  277. err = handleProxyCommand(client.server, client, line)
  278. if err != nil {
  279. break
  280. } else {
  281. continue
  282. }
  283. }
  284. }
  285. msg, err = ircmsg.ParseLineStrict(line, true, maxlenRest)
  286. if err == ircmsg.ErrorLineIsEmpty {
  287. continue
  288. } else if err == ircmsg.ErrorLineTooLong {
  289. client.Send(nil, client.server.name, ERR_INPUTTOOLONG, client.nick, client.t("Input line too long"))
  290. continue
  291. } else if err != nil {
  292. client.Quit(client.t("Received malformed line"))
  293. break
  294. }
  295. cmd, exists := Commands[msg.Command]
  296. if !exists {
  297. if len(msg.Command) > 0 {
  298. client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.nick, msg.Command, client.t("Unknown command"))
  299. } else {
  300. client.Send(nil, client.server.name, ERR_UNKNOWNCOMMAND, client.nick, "lastcmd", client.t("No command given"))
  301. }
  302. continue
  303. }
  304. isExiting = cmd.Run(client.server, client, msg)
  305. if isExiting || client.isQuitting {
  306. break
  307. }
  308. }
  309. }
  310. //
  311. // idle, quit, timers and timeouts
  312. //
  313. // Active updates when the client was last 'active' (i.e. the user should be sitting in front of their client).
  314. func (client *Client) Active() {
  315. client.stateMutex.Lock()
  316. defer client.stateMutex.Unlock()
  317. client.atime = time.Now()
  318. }
  319. // Ping sends the client a PING message.
  320. func (client *Client) Ping() {
  321. client.Send(nil, "", "PING", client.nick)
  322. }
  323. // tryResume tries to resume if the client asked us to.
  324. func (client *Client) tryResume() (success bool) {
  325. server := client.server
  326. config := server.Config()
  327. defer func() {
  328. if !success {
  329. client.resumeDetails = nil
  330. }
  331. }()
  332. timestamp := client.resumeDetails.Timestamp
  333. var timestampString string
  334. if !timestamp.IsZero() {
  335. timestampString = timestamp.UTC().Format(IRCv3TimestampFormat)
  336. }
  337. oldClient := server.resumeManager.VerifyToken(client.resumeDetails.PresentedToken)
  338. if oldClient == nil {
  339. client.Send(nil, server.name, "RESUME", "ERR", client.t("Cannot resume connection, token is not valid"))
  340. return
  341. }
  342. oldNick := oldClient.Nick()
  343. oldNickmask := oldClient.NickMaskString()
  344. resumeAllowed := config.Server.AllowPlaintextResume || (oldClient.HasMode(modes.TLS) && client.HasMode(modes.TLS))
  345. if !resumeAllowed {
  346. client.Send(nil, server.name, "RESUME", "ERR", client.t("Cannot resume connection, old and new clients must have TLS"))
  347. return
  348. }
  349. if oldClient.isTor != client.isTor {
  350. client.Send(nil, server.name, "RESUME", "ERR", client.t("Cannot resume connection from Tor to non-Tor or vice versa"))
  351. return
  352. }
  353. err := server.clients.Resume(client, oldClient)
  354. if err != nil {
  355. client.Send(nil, server.name, "RESUME", "ERR", client.t("Cannot resume connection"))
  356. return
  357. }
  358. success = true
  359. // this is a bit racey
  360. client.resumeDetails.ResumedAt = time.Now()
  361. client.nickTimer.Touch()
  362. // resume successful, proceed to copy client state (nickname, flags, etc.)
  363. // after this, the server thinks that `newClient` owns the nickname
  364. client.resumeDetails.OldClient = oldClient
  365. // transfer monitor stuff
  366. server.monitorManager.Resume(client, oldClient)
  367. // record the names, not the pointers, of the channels,
  368. // to avoid dumb annoying race conditions
  369. channels := oldClient.Channels()
  370. client.resumeDetails.Channels = make([]string, len(channels))
  371. for i, channel := range channels {
  372. client.resumeDetails.Channels[i] = channel.Name()
  373. }
  374. username := client.Username()
  375. hostname := client.Hostname()
  376. friends := make(ClientSet)
  377. oldestLostMessage := time.Now()
  378. // work out how much time, if any, is not covered by history buffers
  379. for _, channel := range channels {
  380. for _, member := range channel.Members() {
  381. friends.Add(member)
  382. lastDiscarded := channel.history.LastDiscarded()
  383. if lastDiscarded.Before(oldestLostMessage) {
  384. oldestLostMessage = lastDiscarded
  385. }
  386. }
  387. }
  388. privmsgMatcher := func(item history.Item) bool {
  389. return item.Type == history.Privmsg || item.Type == history.Notice
  390. }
  391. privmsgHistory := oldClient.history.Match(privmsgMatcher, false, 0)
  392. lastDiscarded := oldClient.history.LastDiscarded()
  393. if lastDiscarded.Before(oldestLostMessage) {
  394. oldestLostMessage = lastDiscarded
  395. }
  396. for _, item := range privmsgHistory {
  397. // TODO this is the nickmask, fix that
  398. sender := server.clients.Get(item.Nick)
  399. if sender != nil {
  400. friends.Add(sender)
  401. }
  402. }
  403. gap := lastDiscarded.Sub(timestamp)
  404. client.resumeDetails.HistoryIncomplete = gap > 0
  405. gapSeconds := int(gap.Seconds()) + 1 // round up to avoid confusion
  406. // send quit/resume messages to friends
  407. for friend := range friends {
  408. if friend.capabilities.Has(caps.Resume) {
  409. if timestamp.IsZero() {
  410. friend.Send(nil, oldNickmask, "RESUMED", username, hostname)
  411. } else {
  412. friend.Send(nil, oldNickmask, "RESUMED", username, hostname, timestampString)
  413. }
  414. } else {
  415. if client.resumeDetails.HistoryIncomplete {
  416. friend.Send(nil, oldNickmask, "QUIT", fmt.Sprintf(friend.t("Client reconnected (up to %d seconds of history lost)"), gapSeconds))
  417. } else {
  418. friend.Send(nil, oldNickmask, "QUIT", fmt.Sprintf(friend.t("Client reconnected")))
  419. }
  420. }
  421. }
  422. if client.resumeDetails.HistoryIncomplete {
  423. client.Send(nil, client.server.name, "RESUME", "WARN", fmt.Sprintf(client.t("Resume may have lost up to %d seconds of history"), gapSeconds))
  424. }
  425. client.Send(nil, client.server.name, "RESUME", "SUCCESS", oldNick)
  426. // after we send the rest of the registration burst, we'll try rejoining channels
  427. return
  428. }
  429. func (client *Client) tryResumeChannels() {
  430. details := client.resumeDetails
  431. channels := make([]*Channel, len(details.Channels))
  432. for _, name := range details.Channels {
  433. channel := client.server.channels.Get(name)
  434. if channel == nil {
  435. continue
  436. }
  437. channel.Resume(client, details.OldClient, details.Timestamp)
  438. channels = append(channels, channel)
  439. }
  440. // replay direct PRIVSMG history
  441. if !details.Timestamp.IsZero() {
  442. now := time.Now()
  443. items, complete := client.history.Between(details.Timestamp, now, false, 0)
  444. rb := NewResponseBuffer(client)
  445. client.replayPrivmsgHistory(rb, items, complete)
  446. rb.Send(true)
  447. }
  448. details.OldClient.destroy(true)
  449. }
  450. func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.Item, complete bool) {
  451. nick := client.Nick()
  452. serverTime := client.capabilities.Has(caps.ServerTime)
  453. for _, item := range items {
  454. var command string
  455. switch item.Type {
  456. case history.Privmsg:
  457. command = "PRIVMSG"
  458. case history.Notice:
  459. command = "NOTICE"
  460. default:
  461. continue
  462. }
  463. var tags map[string]string
  464. if serverTime {
  465. tags = map[string]string{"time": item.Time.Format(IRCv3TimestampFormat)}
  466. }
  467. rb.AddSplitMessageFromClient(item.Nick, item.AccountName, tags, command, nick, item.Message)
  468. }
  469. if !complete {
  470. rb.Add(nil, "HistServ", "NOTICE", nick, client.t("Some additional message history may have been lost"))
  471. }
  472. }
  473. // copy applicable state from oldClient to client as part of a resume
  474. func (client *Client) copyResumeData(oldClient *Client) {
  475. oldClient.stateMutex.RLock()
  476. history := oldClient.history
  477. nick := oldClient.nick
  478. nickCasefolded := oldClient.nickCasefolded
  479. vhost := oldClient.vhost
  480. account := oldClient.account
  481. accountName := oldClient.accountName
  482. skeleton := oldClient.skeleton
  483. oldClient.stateMutex.RUnlock()
  484. // copy all flags, *except* TLS (in the case that the admins enabled
  485. // resume over plaintext)
  486. hasTLS := client.flags.HasMode(modes.TLS)
  487. temp := modes.NewModeSet()
  488. temp.Copy(&oldClient.flags)
  489. temp.SetMode(modes.TLS, hasTLS)
  490. client.flags.Copy(temp)
  491. client.stateMutex.Lock()
  492. defer client.stateMutex.Unlock()
  493. // reuse the old client's history buffer
  494. client.history = history
  495. // copy other data
  496. client.nick = nick
  497. client.nickCasefolded = nickCasefolded
  498. client.vhost = vhost
  499. client.account = account
  500. client.accountName = accountName
  501. client.skeleton = skeleton
  502. client.updateNickMaskNoMutex()
  503. }
  504. // IdleTime returns how long this client's been idle.
  505. func (client *Client) IdleTime() time.Duration {
  506. client.stateMutex.RLock()
  507. defer client.stateMutex.RUnlock()
  508. return time.Since(client.atime)
  509. }
  510. // SignonTime returns this client's signon time as a unix timestamp.
  511. func (client *Client) SignonTime() int64 {
  512. return client.ctime.Unix()
  513. }
  514. // IdleSeconds returns the number of seconds this client's been idle.
  515. func (client *Client) IdleSeconds() uint64 {
  516. return uint64(client.IdleTime().Seconds())
  517. }
  518. // HasNick returns true if the client's nickname is set (used in registration).
  519. func (client *Client) HasNick() bool {
  520. client.stateMutex.RLock()
  521. defer client.stateMutex.RUnlock()
  522. return client.nick != "" && client.nick != "*"
  523. }
  524. // HasUsername returns true if the client's username is set (used in registration).
  525. func (client *Client) HasUsername() bool {
  526. client.stateMutex.RLock()
  527. defer client.stateMutex.RUnlock()
  528. return client.username != "" && client.username != "*"
  529. }
  530. // SetNames sets the client's ident and realname.
  531. func (client *Client) SetNames(username, realname string, fromIdent bool) error {
  532. limit := client.server.Config().Limits.IdentLen
  533. if !fromIdent {
  534. limit -= 1 // leave room for the prepended ~
  535. }
  536. if limit < len(username) {
  537. username = username[:limit]
  538. }
  539. if !isIdent(username) {
  540. return errInvalidUsername
  541. }
  542. if !fromIdent {
  543. username = "~" + username
  544. }
  545. client.stateMutex.Lock()
  546. defer client.stateMutex.Unlock()
  547. if client.username == "" {
  548. client.username = username
  549. }
  550. if client.realname == "" {
  551. client.realname = realname
  552. }
  553. return nil
  554. }
  555. // HasRoleCapabs returns true if client has the given (role) capabilities.
  556. func (client *Client) HasRoleCapabs(capabs ...string) bool {
  557. oper := client.Oper()
  558. if oper == nil {
  559. return false
  560. }
  561. for _, capab := range capabs {
  562. if !oper.Class.Capabilities[capab] {
  563. return false
  564. }
  565. }
  566. return true
  567. }
  568. // ModeString returns the mode string for this client.
  569. func (client *Client) ModeString() (str string) {
  570. return "+" + client.flags.String()
  571. }
  572. // Friends refers to clients that share a channel with this client.
  573. func (client *Client) Friends(capabs ...caps.Capability) ClientSet {
  574. friends := make(ClientSet)
  575. // make sure that I have the right caps
  576. hasCaps := true
  577. for _, capab := range capabs {
  578. if !client.capabilities.Has(capab) {
  579. hasCaps = false
  580. break
  581. }
  582. }
  583. if hasCaps {
  584. friends.Add(client)
  585. }
  586. for _, channel := range client.Channels() {
  587. for _, member := range channel.Members() {
  588. // make sure they have all the required caps
  589. hasCaps = true
  590. for _, capab := range capabs {
  591. if !member.capabilities.Has(capab) {
  592. hasCaps = false
  593. break
  594. }
  595. }
  596. if hasCaps {
  597. friends.Add(member)
  598. }
  599. }
  600. }
  601. return friends
  602. }
  603. func (client *Client) SetOper(oper *Oper) {
  604. client.stateMutex.Lock()
  605. defer client.stateMutex.Unlock()
  606. client.oper = oper
  607. // operators typically get a vhost, update the nickmask
  608. client.updateNickMaskNoMutex()
  609. }
  610. // XXX: CHGHOST requires prefix nickmask to have original hostname,
  611. // this is annoying to do correctly
  612. func (client *Client) sendChghost(oldNickMask string, vhost string) {
  613. username := client.Username()
  614. for fClient := range client.Friends(caps.ChgHost) {
  615. fClient.sendFromClientInternal(false, time.Time{}, "", oldNickMask, client.AccountName(), nil, "CHGHOST", username, vhost)
  616. }
  617. }
  618. // choose the correct vhost to display
  619. func (client *Client) getVHostNoMutex() string {
  620. // hostserv vhost OR operclass vhost OR nothing (i.e., normal rdns hostmask)
  621. if client.vhost != "" {
  622. return client.vhost
  623. } else if client.oper != nil {
  624. return client.oper.Vhost
  625. } else {
  626. return ""
  627. }
  628. }
  629. // SetVHost updates the client's hostserv-based vhost
  630. func (client *Client) SetVHost(vhost string) (updated bool) {
  631. client.stateMutex.Lock()
  632. defer client.stateMutex.Unlock()
  633. updated = (client.vhost != vhost)
  634. client.vhost = vhost
  635. if updated {
  636. client.updateNickMaskNoMutex()
  637. }
  638. return
  639. }
  640. // updateNick updates `nick` and `nickCasefolded`.
  641. func (client *Client) updateNick(nick, nickCasefolded, skeleton string) {
  642. client.stateMutex.Lock()
  643. defer client.stateMutex.Unlock()
  644. client.nick = nick
  645. client.nickCasefolded = nickCasefolded
  646. client.skeleton = skeleton
  647. client.updateNickMaskNoMutex()
  648. }
  649. // updateNickMaskNoMutex updates the casefolded nickname and nickmask, not acquiring any mutexes.
  650. func (client *Client) updateNickMaskNoMutex() {
  651. client.hostname = client.getVHostNoMutex()
  652. if client.hostname == "" {
  653. client.hostname = client.rawHostname
  654. }
  655. cfhostname, err := Casefold(client.hostname)
  656. if err != nil {
  657. client.server.logger.Error("internal", "hostname couldn't be casefolded", client.hostname, err.Error())
  658. cfhostname = client.hostname // YOLO
  659. }
  660. client.nickMaskString = fmt.Sprintf("%s!%s@%s", client.nick, client.username, client.hostname)
  661. client.nickMaskCasefolded = fmt.Sprintf("%s!%s@%s", client.nickCasefolded, strings.ToLower(client.username), cfhostname)
  662. }
  663. // AllNickmasks returns all the possible nickmasks for the client.
  664. func (client *Client) AllNickmasks() (masks []string) {
  665. client.stateMutex.RLock()
  666. nick := client.nickCasefolded
  667. username := client.username
  668. rawHostname := client.rawHostname
  669. vhost := client.getVHostNoMutex()
  670. client.stateMutex.RUnlock()
  671. username = strings.ToLower(username)
  672. if len(vhost) > 0 {
  673. cfvhost, err := Casefold(vhost)
  674. if err == nil {
  675. masks = append(masks, fmt.Sprintf("%s!%s@%s", nick, username, cfvhost))
  676. }
  677. }
  678. var rawhostmask string
  679. cfrawhost, err := Casefold(rawHostname)
  680. if err == nil {
  681. rawhostmask = fmt.Sprintf("%s!%s@%s", nick, username, cfrawhost)
  682. masks = append(masks, rawhostmask)
  683. }
  684. ipmask := fmt.Sprintf("%s!%s@%s", nick, username, client.IPString())
  685. if ipmask != rawhostmask {
  686. masks = append(masks, ipmask)
  687. }
  688. return
  689. }
  690. // LoggedIntoAccount returns true if this client is logged into an account.
  691. func (client *Client) LoggedIntoAccount() bool {
  692. return client.Account() != ""
  693. }
  694. // RplISupport outputs our ISUPPORT lines to the client. This is used on connection and in VERSION responses.
  695. func (client *Client) RplISupport(rb *ResponseBuffer) {
  696. translatedISupport := client.t("are supported by this server")
  697. nick := client.Nick()
  698. for _, cachedTokenLine := range client.server.ISupport().CachedReply {
  699. length := len(cachedTokenLine) + 2
  700. tokenline := make([]string, length)
  701. tokenline[0] = nick
  702. copy(tokenline[1:], cachedTokenLine)
  703. tokenline[length-1] = translatedISupport
  704. rb.Add(nil, client.server.name, RPL_ISUPPORT, tokenline...)
  705. }
  706. }
  707. // Quit sets the given quit message for the client.
  708. // (You must ensure separately that destroy() is called, e.g., by returning `true` from
  709. // the command handler or calling it yourself.)
  710. func (client *Client) Quit(message string) {
  711. client.stateMutex.Lock()
  712. alreadyQuit := client.isQuitting
  713. if !alreadyQuit {
  714. client.isQuitting = true
  715. client.quitMessage = message
  716. }
  717. registered := client.registered
  718. prefix := client.nickMaskString
  719. client.stateMutex.Unlock()
  720. if alreadyQuit {
  721. return
  722. }
  723. var finalData []byte
  724. // #364: don't send QUIT lines to unregistered clients
  725. if registered {
  726. quitMsg := ircmsg.MakeMessage(nil, prefix, "QUIT", message)
  727. finalData, _ = quitMsg.LineBytesStrict(false, 512)
  728. }
  729. errorMsg := ircmsg.MakeMessage(nil, "", "ERROR", message)
  730. errorMsgBytes, _ := errorMsg.LineBytesStrict(false, 512)
  731. finalData = append(finalData, errorMsgBytes...)
  732. client.socket.SetFinalData(finalData)
  733. }
  734. // destroy gets rid of a client, removes them from server lists etc.
  735. func (client *Client) destroy(beingResumed bool) {
  736. // allow destroy() to execute at most once
  737. client.stateMutex.Lock()
  738. isDestroyed := client.isDestroyed
  739. client.isDestroyed = true
  740. quitMessage := client.quitMessage
  741. nickMaskString := client.nickMaskString
  742. accountName := client.accountName
  743. client.stateMutex.Unlock()
  744. if isDestroyed {
  745. return
  746. }
  747. // see #235: deduplicating the list of PART recipients uses (comparatively speaking)
  748. // a lot of RAM, so limit concurrency to avoid thrashing
  749. client.server.semaphores.ClientDestroy.Acquire()
  750. defer client.server.semaphores.ClientDestroy.Release()
  751. if beingResumed {
  752. client.server.logger.Debug("quit", fmt.Sprintf("%s is being resumed", client.nick))
  753. } else {
  754. client.server.logger.Debug("quit", fmt.Sprintf("%s is no longer on the server", client.nick))
  755. }
  756. // send quit/error message to client if they haven't been sent already
  757. client.Quit("Connection closed")
  758. if !beingResumed {
  759. client.server.whoWas.Append(client.WhoWas())
  760. }
  761. // remove from connection limits
  762. if client.isTor {
  763. client.server.torLimiter.RemoveClient()
  764. } else {
  765. client.server.connectionLimiter.RemoveClient(client.IP())
  766. }
  767. client.server.resumeManager.Delete(client)
  768. // alert monitors
  769. client.server.monitorManager.AlertAbout(client, false)
  770. // clean up monitor state
  771. client.server.monitorManager.RemoveAll(client)
  772. // clean up channels
  773. friends := make(ClientSet)
  774. for _, channel := range client.Channels() {
  775. if !beingResumed {
  776. channel.Quit(client)
  777. channel.history.Add(history.Item{
  778. Type: history.Quit,
  779. Nick: nickMaskString,
  780. AccountName: accountName,
  781. Message: utils.MakeSplitMessage(quitMessage, true),
  782. })
  783. }
  784. for _, member := range channel.Members() {
  785. friends.Add(member)
  786. }
  787. }
  788. friends.Remove(client)
  789. // clean up server
  790. if !beingResumed {
  791. client.server.clients.Remove(client)
  792. }
  793. // clean up self
  794. client.idletimer.Stop()
  795. client.nickTimer.Stop()
  796. client.server.accounts.Logout(client)
  797. client.socket.Close()
  798. // send quit messages to friends
  799. if !beingResumed {
  800. if client.Registered() {
  801. client.server.stats.ChangeTotal(-1)
  802. }
  803. if client.HasMode(modes.Invisible) {
  804. client.server.stats.ChangeInvisible(-1)
  805. }
  806. if client.HasMode(modes.Operator) || client.HasMode(modes.LocalOperator) {
  807. client.server.stats.ChangeOperators(-1)
  808. }
  809. for friend := range friends {
  810. if quitMessage == "" {
  811. quitMessage = "Exited"
  812. }
  813. friend.Send(nil, client.nickMaskString, "QUIT", quitMessage)
  814. }
  815. }
  816. if !client.exitedSnomaskSent {
  817. if beingResumed {
  818. client.server.snomasks.Send(sno.LocalQuits, fmt.Sprintf(ircfmt.Unescape("%s$r is resuming their connection, old client has been destroyed"), client.nick))
  819. } else {
  820. client.server.snomasks.Send(sno.LocalQuits, fmt.Sprintf(ircfmt.Unescape("%s$r exited the network"), client.nick))
  821. }
  822. }
  823. }
  824. // SendSplitMsgFromClient sends an IRC PRIVMSG/NOTICE coming from a specific client.
  825. // Adds account-tag to the line as well.
  826. func (client *Client) SendSplitMsgFromClient(from *Client, tags map[string]string, command, target string, message utils.SplitMessage) {
  827. client.sendSplitMsgFromClientInternal(false, time.Time{}, from.NickMaskString(), from.AccountName(), tags, command, target, message)
  828. }
  829. func (client *Client) sendSplitMsgFromClientInternal(blocking bool, serverTime time.Time, nickmask, accountName string, tags map[string]string, command, target string, message utils.SplitMessage) {
  830. if client.capabilities.Has(caps.MaxLine) || message.Wrapped == nil {
  831. client.sendFromClientInternal(blocking, serverTime, message.Msgid, nickmask, accountName, tags, command, target, message.Message)
  832. } else {
  833. for _, messagePair := range message.Wrapped {
  834. client.sendFromClientInternal(blocking, serverTime, messagePair.Msgid, nickmask, accountName, tags, command, target, messagePair.Message)
  835. }
  836. }
  837. }
  838. // SendFromClient sends an IRC line coming from a specific client.
  839. // Adds account-tag to the line as well.
  840. func (client *Client) SendFromClient(msgid string, from *Client, tags map[string]string, command string, params ...string) error {
  841. return client.sendFromClientInternal(false, time.Time{}, msgid, from.NickMaskString(), from.AccountName(), tags, command, params...)
  842. }
  843. // this is SendFromClient, but directly exposing nickmask and accountName,
  844. // for things like history replay and CHGHOST where they no longer (necessarily)
  845. // correspond to the current state of a client
  846. func (client *Client) sendFromClientInternal(blocking bool, serverTime time.Time, msgid string, nickmask, accountName string, tags map[string]string, command string, params ...string) error {
  847. msg := ircmsg.MakeMessage(tags, nickmask, command, params...)
  848. // attach account-tag
  849. if client.capabilities.Has(caps.AccountTag) && accountName != "*" {
  850. msg.SetTag("account", accountName)
  851. }
  852. // attach message-id
  853. if msgid != "" && client.capabilities.Has(caps.MessageTags) {
  854. msg.SetTag("draft/msgid", msgid)
  855. }
  856. // attach server-time
  857. if client.capabilities.Has(caps.ServerTime) {
  858. msg.SetTag("time", time.Now().UTC().Format(IRCv3TimestampFormat))
  859. }
  860. return client.SendRawMessage(msg, blocking)
  861. }
  862. var (
  863. // these are all the output commands that MUST have their last param be a trailing.
  864. // this is needed because dumb clients like to treat trailing params separately from the
  865. // other params in messages.
  866. commandsThatMustUseTrailing = map[string]bool{
  867. "PRIVMSG": true,
  868. "NOTICE": true,
  869. RPL_WHOISCHANNELS: true,
  870. RPL_USERHOST: true,
  871. }
  872. )
  873. // SendRawMessage sends a raw message to the client.
  874. func (client *Client) SendRawMessage(message ircmsg.IrcMessage, blocking bool) error {
  875. // use dumb hack to force the last param to be a trailing param if required
  876. var usedTrailingHack bool
  877. if commandsThatMustUseTrailing[message.Command] && len(message.Params) > 0 {
  878. lastParam := message.Params[len(message.Params)-1]
  879. // to force trailing, we ensure the final param contains a space
  880. if strings.IndexByte(lastParam, ' ') == -1 {
  881. message.Params[len(message.Params)-1] = lastParam + " "
  882. usedTrailingHack = true
  883. }
  884. }
  885. // assemble message
  886. maxlenRest := client.MaxlenRest()
  887. line, err := message.LineBytesStrict(false, maxlenRest)
  888. if err != nil {
  889. logline := fmt.Sprintf("Error assembling message for sending: %v\n%s", err, debug.Stack())
  890. client.server.logger.Error("internal", logline)
  891. message = ircmsg.MakeMessage(nil, client.server.name, ERR_UNKNOWNERROR, "*", "Error assembling message for sending")
  892. line, _ := message.LineBytesStrict(false, 0)
  893. if blocking {
  894. client.socket.BlockingWrite(line)
  895. } else {
  896. client.socket.Write(line)
  897. }
  898. return err
  899. }
  900. // if we used the trailing hack, we need to strip the final space we appended earlier on
  901. if usedTrailingHack {
  902. copy(line[len(line)-3:], "\r\n")
  903. line = line[:len(line)-1]
  904. }
  905. if client.server.logger.IsLoggingRawIO() {
  906. logline := string(line[:len(line)-2]) // strip "\r\n"
  907. client.server.logger.Debug("useroutput", client.nick, " ->", logline)
  908. }
  909. if blocking {
  910. return client.socket.BlockingWrite(line)
  911. } else {
  912. return client.socket.Write(line)
  913. }
  914. }
  915. // Send sends an IRC line to the client.
  916. func (client *Client) Send(tags map[string]string, prefix string, command string, params ...string) error {
  917. msg := ircmsg.MakeMessage(tags, prefix, command, params...)
  918. if client.capabilities.Has(caps.ServerTime) && !msg.HasTag("time") {
  919. msg.SetTag("time", time.Now().UTC().Format(IRCv3TimestampFormat))
  920. }
  921. return client.SendRawMessage(msg, false)
  922. }
  923. // Notice sends the client a notice from the server.
  924. func (client *Client) Notice(text string) {
  925. limit := 400
  926. if client.capabilities.Has(caps.MaxLine) {
  927. limit = client.server.Limits().LineLen.Rest - 110
  928. }
  929. lines := utils.WordWrap(text, limit)
  930. // force blank lines to be sent if we receive them
  931. if len(lines) == 0 {
  932. lines = []string{""}
  933. }
  934. for _, line := range lines {
  935. client.Send(nil, client.server.name, "NOTICE", client.nick, line)
  936. }
  937. }
  938. func (client *Client) addChannel(channel *Channel) {
  939. client.stateMutex.Lock()
  940. client.channels[channel] = true
  941. client.stateMutex.Unlock()
  942. }
  943. func (client *Client) removeChannel(channel *Channel) {
  944. client.stateMutex.Lock()
  945. delete(client.channels, channel)
  946. client.stateMutex.Unlock()
  947. }
  948. // Records that the client has been invited to join an invite-only channel
  949. func (client *Client) Invite(casefoldedChannel string) {
  950. client.stateMutex.Lock()
  951. defer client.stateMutex.Unlock()
  952. if client.invitedTo == nil {
  953. client.invitedTo = make(map[string]bool)
  954. }
  955. client.invitedTo[casefoldedChannel] = true
  956. }
  957. // Checks that the client was invited to join a given channel
  958. func (client *Client) CheckInvited(casefoldedChannel string) (invited bool) {
  959. client.stateMutex.Lock()
  960. defer client.stateMutex.Unlock()
  961. invited = client.invitedTo[casefoldedChannel]
  962. // joining an invited channel "uses up" your invite, so you can't rejoin on kick
  963. delete(client.invitedTo, casefoldedChannel)
  964. return
  965. }