您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

client.go 37KB

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