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 37KB

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