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

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