Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

server.go 33KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  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. "bufio"
  8. "crypto/tls"
  9. "fmt"
  10. "net"
  11. "net/http"
  12. _ "net/http/pprof"
  13. "os"
  14. "os/signal"
  15. "strconv"
  16. "strings"
  17. "sync"
  18. "syscall"
  19. "time"
  20. "unsafe"
  21. "github.com/goshuirc/irc-go/ircfmt"
  22. "github.com/oragono/oragono/irc/caps"
  23. "github.com/oragono/oragono/irc/connection_limits"
  24. "github.com/oragono/oragono/irc/logger"
  25. "github.com/oragono/oragono/irc/modes"
  26. "github.com/oragono/oragono/irc/sno"
  27. "github.com/tidwall/buntdb"
  28. )
  29. var (
  30. // common error line to sub values into
  31. errorMsg = "ERROR :%s\r\n"
  32. // supportedUserModesString acts as a cache for when we introduce users
  33. supportedUserModesString = modes.SupportedUserModes.String()
  34. // supportedChannelModesString acts as a cache for when we introduce users
  35. supportedChannelModesString = modes.SupportedChannelModes.String()
  36. // SupportedCapabilities are the caps we advertise.
  37. // MaxLine, SASL and STS may be unset during server startup / rehash.
  38. SupportedCapabilities = caps.NewCompleteSet()
  39. // CapValues are the actual values we advertise to v3.2 clients.
  40. // actual values are set during server startup.
  41. CapValues = caps.NewValues()
  42. )
  43. // ListenerWrapper wraps a listener so it can be safely reconfigured or stopped
  44. type ListenerWrapper struct {
  45. // protects atomic update of config and shouldStop:
  46. sync.Mutex // tier 1
  47. listener net.Listener
  48. config listenerConfig
  49. shouldStop bool
  50. }
  51. // Server is the main Oragono server.
  52. type Server struct {
  53. accounts AccountManager
  54. channels ChannelManager
  55. channelRegistry ChannelRegistry
  56. clients ClientManager
  57. config unsafe.Pointer
  58. configFilename string
  59. connectionLimiter connection_limits.Limiter
  60. connectionThrottler connection_limits.Throttler
  61. ctime time.Time
  62. dlines *DLineManager
  63. helpIndexManager HelpIndexManager
  64. klines *KLineManager
  65. listeners map[string]*ListenerWrapper
  66. logger *logger.Manager
  67. monitorManager MonitorManager
  68. name string
  69. nameCasefolded string
  70. rehashMutex sync.Mutex // tier 4
  71. rehashSignal chan os.Signal
  72. pprofServer *http.Server
  73. resumeManager ResumeManager
  74. signals chan os.Signal
  75. snomasks SnoManager
  76. store *buntdb.DB
  77. torLimiter connection_limits.TorLimiter
  78. whoWas WhoWasList
  79. stats Stats
  80. semaphores ServerSemaphores
  81. }
  82. var (
  83. // ServerExitSignals are the signals the server will exit on.
  84. ServerExitSignals = []os.Signal{
  85. syscall.SIGINT,
  86. syscall.SIGTERM,
  87. syscall.SIGQUIT,
  88. }
  89. )
  90. type clientConn struct {
  91. Conn net.Conn
  92. Config listenerConfig
  93. }
  94. // NewServer returns a new Oragono server.
  95. func NewServer(config *Config, logger *logger.Manager) (*Server, error) {
  96. // initialize data structures
  97. server := &Server{
  98. ctime: time.Now().UTC(),
  99. listeners: make(map[string]*ListenerWrapper),
  100. logger: logger,
  101. rehashSignal: make(chan os.Signal, 1),
  102. signals: make(chan os.Signal, len(ServerExitSignals)),
  103. }
  104. server.clients.Initialize()
  105. server.semaphores.Initialize()
  106. server.resumeManager.Initialize(server)
  107. server.whoWas.Initialize(config.Limits.WhowasEntries)
  108. server.monitorManager.Initialize()
  109. server.snomasks.Initialize()
  110. if err := server.applyConfig(config, true); err != nil {
  111. return nil, err
  112. }
  113. // Attempt to clean up when receiving these signals.
  114. signal.Notify(server.signals, ServerExitSignals...)
  115. signal.Notify(server.rehashSignal, syscall.SIGHUP)
  116. return server, nil
  117. }
  118. // setISupport sets up our RPL_ISUPPORT reply.
  119. func (config *Config) generateISupport() (err error) {
  120. maxTargetsString := strconv.Itoa(maxTargets)
  121. // add RPL_ISUPPORT tokens
  122. isupport := &config.Server.isupport
  123. isupport.Initialize()
  124. isupport.Add("AWAYLEN", strconv.Itoa(config.Limits.AwayLen))
  125. isupport.Add("CASEMAPPING", "ascii")
  126. isupport.Add("CHANMODES", strings.Join([]string{modes.Modes{modes.BanMask, modes.ExceptMask, modes.InviteMask}.String(), "", modes.Modes{modes.UserLimit, modes.Key}.String(), modes.Modes{modes.InviteOnly, modes.Moderated, modes.NoOutside, modes.OpOnlyTopic, modes.ChanRoleplaying, modes.Secret}.String()}, ","))
  127. if config.History.Enabled && config.History.ChathistoryMax > 0 {
  128. isupport.Add("draft/CHATHISTORY", strconv.Itoa(config.History.ChathistoryMax))
  129. }
  130. isupport.Add("CHANNELLEN", strconv.Itoa(config.Limits.ChannelLen))
  131. isupport.Add("CHANTYPES", "#")
  132. isupport.Add("ELIST", "U")
  133. isupport.Add("EXCEPTS", "")
  134. isupport.Add("INVEX", "")
  135. isupport.Add("KICKLEN", strconv.Itoa(config.Limits.KickLen))
  136. isupport.Add("MAXLIST", fmt.Sprintf("beI:%s", strconv.Itoa(config.Limits.ChanListModes)))
  137. isupport.Add("MAXTARGETS", maxTargetsString)
  138. isupport.Add("MODES", "")
  139. isupport.Add("MONITOR", strconv.Itoa(config.Limits.MonitorEntries))
  140. isupport.Add("NETWORK", config.Network.Name)
  141. isupport.Add("NICKLEN", strconv.Itoa(config.Limits.NickLen))
  142. isupport.Add("PREFIX", "(qaohv)~&@%+")
  143. isupport.Add("RPCHAN", "E")
  144. isupport.Add("RPUSER", "E")
  145. isupport.Add("STATUSMSG", "~&@%+")
  146. isupport.Add("TARGMAX", fmt.Sprintf("NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:%s,TAGMSG:%s,NOTICE:%s,MONITOR:", maxTargetsString, maxTargetsString, maxTargetsString))
  147. isupport.Add("TOPICLEN", strconv.Itoa(config.Limits.TopicLen))
  148. isupport.Add("UTF8MAPPING", casemappingName)
  149. err = isupport.RegenerateCachedReply()
  150. return
  151. }
  152. // Shutdown shuts down the server.
  153. func (server *Server) Shutdown() {
  154. //TODO(dan): Make sure we disallow new nicks
  155. for _, client := range server.clients.AllClients() {
  156. client.Notice("Server is shutting down")
  157. }
  158. if err := server.store.Close(); err != nil {
  159. server.logger.Error("shutdown", fmt.Sprintln("Could not close datastore:", err))
  160. }
  161. }
  162. // Run starts the server.
  163. func (server *Server) Run() {
  164. // defer closing db/store
  165. defer server.store.Close()
  166. for {
  167. select {
  168. case <-server.signals:
  169. server.Shutdown()
  170. return
  171. case <-server.rehashSignal:
  172. go func() {
  173. server.logger.Info("server", "Rehashing due to SIGHUP")
  174. err := server.rehash()
  175. if err != nil {
  176. server.logger.Error("server", fmt.Sprintln("Failed to rehash:", err.Error()))
  177. }
  178. }()
  179. }
  180. }
  181. }
  182. func (server *Server) checkBans(ipaddr net.IP) (banned bool, message string) {
  183. // check DLINEs
  184. isBanned, info := server.dlines.CheckIP(ipaddr)
  185. if isBanned {
  186. server.logger.Info("localconnect-ip", fmt.Sprintf("Client from %v rejected by d-line", ipaddr))
  187. return true, info.BanMessage("You are banned from this server (%s)")
  188. }
  189. // check connection limits
  190. err := server.connectionLimiter.AddClient(ipaddr, false)
  191. if err != nil {
  192. // too many connections from one client, tell the client and close the connection
  193. server.logger.Info("localconnect-ip", fmt.Sprintf("Client from %v rejected for connection limit", ipaddr))
  194. return true, "Too many clients from your network"
  195. }
  196. // check connection throttle
  197. err = server.connectionThrottler.AddClient(ipaddr)
  198. if err != nil {
  199. // too many connections too quickly from client, tell them and close the connection
  200. duration := server.connectionThrottler.BanDuration()
  201. if duration == 0 {
  202. return false, ""
  203. }
  204. server.dlines.AddIP(ipaddr, duration, server.connectionThrottler.BanMessage(), "Exceeded automated connection throttle", "auto.connection.throttler")
  205. // they're DLINE'd for 15 minutes or whatever, so we can reset the connection throttle now,
  206. // and once their temporary DLINE is finished they can fill up the throttler again
  207. server.connectionThrottler.ResetFor(ipaddr)
  208. // this might not show up properly on some clients, but our objective here is just to close it out before it has a load impact on us
  209. server.logger.Info(
  210. "localconnect-ip",
  211. fmt.Sprintf("Client from %v exceeded connection throttle, d-lining for %v", ipaddr, duration))
  212. return true, server.connectionThrottler.BanMessage()
  213. }
  214. return false, ""
  215. }
  216. func (server *Server) checkTorLimits() (banned bool, message string) {
  217. switch server.torLimiter.AddClient() {
  218. case connection_limits.ErrLimitExceeded:
  219. return true, "Too many clients from the Tor network"
  220. case connection_limits.ErrThrottleExceeded:
  221. return true, "Exceeded connection throttle for the Tor network"
  222. default:
  223. return false, ""
  224. }
  225. }
  226. //
  227. // IRC protocol listeners
  228. //
  229. // createListener starts a given listener.
  230. func (server *Server) createListener(addr string, conf listenerConfig, bindMode os.FileMode) (*ListenerWrapper, error) {
  231. // make listener
  232. var listener net.Listener
  233. var err error
  234. addr = strings.TrimPrefix(addr, "unix:")
  235. if strings.HasPrefix(addr, "/") {
  236. // https://stackoverflow.com/a/34881585
  237. os.Remove(addr)
  238. listener, err = net.Listen("unix", addr)
  239. if err == nil && bindMode != 0 {
  240. os.Chmod(addr, bindMode)
  241. }
  242. } else {
  243. listener, err = net.Listen("tcp", addr)
  244. }
  245. if err != nil {
  246. return nil, err
  247. }
  248. // throw our details to the server so we can be modified/killed later
  249. wrapper := ListenerWrapper{
  250. listener: listener,
  251. config: conf,
  252. shouldStop: false,
  253. }
  254. var shouldStop bool
  255. // setup accept goroutine
  256. go func() {
  257. for {
  258. conn, err := listener.Accept()
  259. // synchronously access config data:
  260. wrapper.Lock()
  261. shouldStop = wrapper.shouldStop
  262. conf := wrapper.config
  263. wrapper.Unlock()
  264. if shouldStop {
  265. if conn != nil {
  266. conn.Close()
  267. }
  268. listener.Close()
  269. return
  270. } else if err == nil {
  271. if conf.TLSConfig != nil {
  272. conn = tls.Server(conn, conf.TLSConfig)
  273. }
  274. newConn := clientConn{
  275. Conn: conn,
  276. Config: conf,
  277. }
  278. // hand off the connection
  279. go server.RunClient(newConn)
  280. } else {
  281. server.logger.Error("internal", "accept error", addr, err.Error())
  282. }
  283. }
  284. }()
  285. return &wrapper, nil
  286. }
  287. //
  288. // server functionality
  289. //
  290. func (server *Server) tryRegister(c *Client, session *Session) (exiting bool) {
  291. // if the session just sent us a RESUME line, try to resume
  292. if session.resumeDetails != nil {
  293. session.tryResume()
  294. return // whether we succeeded or failed, either way `c` is not getting registered
  295. }
  296. // try to complete registration normally
  297. if c.preregNick == "" || !c.HasUsername() || session.capState == caps.NegotiatingState {
  298. return
  299. }
  300. // client MUST send PASS if necessary, or authenticate with SASL if necessary,
  301. // before completing the other registration commands
  302. authOutcome := c.isAuthorized(server.Config())
  303. var quitMessage string
  304. switch authOutcome {
  305. case authFailPass:
  306. quitMessage = c.t("Password incorrect")
  307. c.Send(nil, server.name, ERR_PASSWDMISMATCH, "*", quitMessage)
  308. case authFailSaslRequired, authFailTorSaslRequired:
  309. quitMessage = c.t("You must log in with SASL to join this server")
  310. c.Send(nil, c.server.name, "FAIL", "*", "ACCOUNT_REQUIRED", quitMessage)
  311. }
  312. if authOutcome != authSuccess {
  313. c.Quit(quitMessage, nil)
  314. return true
  315. }
  316. rb := NewResponseBuffer(session)
  317. nickAssigned := performNickChange(server, c, c, session, c.preregNick, rb)
  318. rb.Send(true)
  319. if !nickAssigned {
  320. c.preregNick = ""
  321. return
  322. }
  323. // check KLINEs
  324. isBanned, info := server.klines.CheckMasks(c.AllNickmasks()...)
  325. if isBanned {
  326. c.Quit(info.BanMessage(c.t("You are banned from this server (%s)")), nil)
  327. return true
  328. }
  329. if session.client != c {
  330. // reattached, bail out.
  331. // we'll play the reg burst later, on the new goroutine associated with
  332. // (thisSession, otherClient). This is to avoid having to transfer state
  333. // like nickname, hostname, etc. to show the correct values in the reg burst.
  334. return
  335. }
  336. // registration has succeeded:
  337. c.SetRegistered()
  338. // count new user in statistics
  339. server.stats.Register()
  340. server.monitorManager.AlertAbout(c, true)
  341. server.playRegistrationBurst(session)
  342. return false
  343. }
  344. func (server *Server) playRegistrationBurst(session *Session) {
  345. c := session.client
  346. // continue registration
  347. d := c.Details()
  348. server.logger.Info("localconnect", fmt.Sprintf("Client connected [%s] [u:%s] [r:%s]", d.nick, d.username, d.realname))
  349. server.snomasks.Send(sno.LocalConnects, fmt.Sprintf("Client connected [%s] [u:%s] [h:%s] [ip:%s] [r:%s]", d.nick, d.username, c.RawHostname(), c.IPString(), d.realname))
  350. // send welcome text
  351. //NOTE(dan): we specifically use the NICK here instead of the nickmask
  352. // see http://modern.ircdocs.horse/#rplwelcome-001 for details on why we avoid using the nickmask
  353. session.Send(nil, server.name, RPL_WELCOME, d.nick, fmt.Sprintf(c.t("Welcome to the Internet Relay Network %s"), d.nick))
  354. session.Send(nil, server.name, RPL_YOURHOST, d.nick, fmt.Sprintf(c.t("Your host is %[1]s, running version %[2]s"), server.name, Ver))
  355. session.Send(nil, server.name, RPL_CREATED, d.nick, fmt.Sprintf(c.t("This server was created %s"), server.ctime.Format(time.RFC1123)))
  356. //TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
  357. session.Send(nil, server.name, RPL_MYINFO, d.nick, server.name, Ver, supportedUserModesString, supportedChannelModesString)
  358. rb := NewResponseBuffer(session)
  359. server.RplISupport(c, rb)
  360. server.Lusers(c, rb)
  361. server.MOTD(c, rb)
  362. rb.Send(true)
  363. modestring := c.ModeString()
  364. if modestring != "+" {
  365. session.Send(nil, d.nickMask, RPL_UMODEIS, d.nick, modestring)
  366. }
  367. if server.logger.IsLoggingRawIO() {
  368. session.Send(nil, c.server.name, "NOTICE", d.nick, c.t("This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
  369. }
  370. // #572: defer nick warnings to the end of the registration burst
  371. session.client.nickTimer.Touch(nil)
  372. }
  373. // RplISupport outputs our ISUPPORT lines to the client. This is used on connection and in VERSION responses.
  374. func (server *Server) RplISupport(client *Client, rb *ResponseBuffer) {
  375. translatedISupport := client.t("are supported by this server")
  376. nick := client.Nick()
  377. config := server.Config()
  378. for _, cachedTokenLine := range config.Server.isupport.CachedReply {
  379. length := len(cachedTokenLine) + 2
  380. tokenline := make([]string, length)
  381. tokenline[0] = nick
  382. copy(tokenline[1:], cachedTokenLine)
  383. tokenline[length-1] = translatedISupport
  384. rb.Add(nil, server.name, RPL_ISUPPORT, tokenline...)
  385. }
  386. }
  387. func (server *Server) Lusers(client *Client, rb *ResponseBuffer) {
  388. nick := client.Nick()
  389. stats := server.stats.GetValues()
  390. rb.Add(nil, server.name, RPL_LUSERCLIENT, nick, fmt.Sprintf(client.t("There are %[1]d users and %[2]d invisible on %[3]d server(s)"), stats.Total-stats.Invisible, stats.Invisible, 1))
  391. rb.Add(nil, server.name, RPL_LUSEROP, nick, strconv.Itoa(stats.Operators), client.t("IRC Operators online"))
  392. rb.Add(nil, server.name, RPL_LUSERUNKNOWN, nick, strconv.Itoa(stats.Unknown), client.t("unregistered connections"))
  393. rb.Add(nil, server.name, RPL_LUSERCHANNELS, nick, strconv.Itoa(server.channels.Len()), client.t("channels formed"))
  394. rb.Add(nil, server.name, RPL_LUSERME, nick, fmt.Sprintf(client.t("I have %[1]d clients and %[2]d servers"), stats.Total, 1))
  395. total := strconv.Itoa(stats.Total)
  396. max := strconv.Itoa(stats.Max)
  397. rb.Add(nil, server.name, RPL_LOCALUSERS, nick, total, max, fmt.Sprintf(client.t("Current local users %[1]s, max %[2]s"), total, max))
  398. rb.Add(nil, server.name, RPL_GLOBALUSERS, nick, total, max, fmt.Sprintf(client.t("Current global users %[1]s, max %[2]s"), total, max))
  399. }
  400. // MOTD serves the Message of the Day.
  401. func (server *Server) MOTD(client *Client, rb *ResponseBuffer) {
  402. motdLines := server.Config().Server.motdLines
  403. if len(motdLines) < 1 {
  404. rb.Add(nil, server.name, ERR_NOMOTD, client.nick, client.t("MOTD File is missing"))
  405. return
  406. }
  407. rb.Add(nil, server.name, RPL_MOTDSTART, client.nick, fmt.Sprintf(client.t("- %s Message of the day - "), server.name))
  408. for _, line := range motdLines {
  409. rb.Add(nil, server.name, RPL_MOTD, client.nick, line)
  410. }
  411. rb.Add(nil, server.name, RPL_ENDOFMOTD, client.nick, client.t("End of MOTD command"))
  412. }
  413. // WhoisChannelsNames returns the common channel names between two users.
  414. func (client *Client) WhoisChannelsNames(target *Client, multiPrefix bool) []string {
  415. var chstrs []string
  416. for _, channel := range target.Channels() {
  417. // channel is secret and the target can't see it
  418. if !client.HasMode(modes.Operator) {
  419. if (target.HasMode(modes.Invisible) || channel.flags.HasMode(modes.Secret)) && !channel.hasClient(client) {
  420. continue
  421. }
  422. }
  423. chstrs = append(chstrs, channel.ClientPrefixes(target, multiPrefix)+channel.name)
  424. }
  425. return chstrs
  426. }
  427. func (client *Client) getWhoisOf(target *Client, rb *ResponseBuffer) {
  428. cnick := client.Nick()
  429. targetInfo := target.Details()
  430. rb.Add(nil, client.server.name, RPL_WHOISUSER, cnick, targetInfo.nick, targetInfo.username, targetInfo.hostname, "*", targetInfo.realname)
  431. tnick := targetInfo.nick
  432. whoischannels := client.WhoisChannelsNames(target, rb.session.capabilities.Has(caps.MultiPrefix))
  433. if whoischannels != nil {
  434. rb.Add(nil, client.server.name, RPL_WHOISCHANNELS, cnick, tnick, strings.Join(whoischannels, " "))
  435. }
  436. tOper := target.Oper()
  437. if tOper != nil {
  438. rb.Add(nil, client.server.name, RPL_WHOISOPERATOR, cnick, tnick, tOper.WhoisLine)
  439. }
  440. if client.HasMode(modes.Operator) || client == target {
  441. rb.Add(nil, client.server.name, RPL_WHOISACTUALLY, cnick, tnick, fmt.Sprintf("%s@%s", targetInfo.username, target.RawHostname()), target.IPString(), client.t("Actual user@host, Actual IP"))
  442. }
  443. if target.HasMode(modes.TLS) {
  444. rb.Add(nil, client.server.name, RPL_WHOISSECURE, cnick, tnick, client.t("is using a secure connection"))
  445. }
  446. if targetInfo.accountName != "*" {
  447. rb.Add(nil, client.server.name, RPL_WHOISACCOUNT, cnick, tnick, targetInfo.accountName, client.t("is logged in as"))
  448. }
  449. if target.HasMode(modes.Bot) {
  450. rb.Add(nil, client.server.name, RPL_WHOISBOT, cnick, tnick, ircfmt.Unescape(fmt.Sprintf(client.t("is a $bBot$b on %s"), client.server.Config().Network.Name)))
  451. }
  452. if target.certfp != "" && (client.HasMode(modes.Operator) || client == target) {
  453. rb.Add(nil, client.server.name, RPL_WHOISCERTFP, cnick, tnick, fmt.Sprintf(client.t("has client certificate fingerprint %s"), target.certfp))
  454. }
  455. rb.Add(nil, client.server.name, RPL_WHOISIDLE, cnick, tnick, strconv.FormatUint(target.IdleSeconds(), 10), strconv.FormatInt(target.SignonTime(), 10), client.t("seconds idle, signon time"))
  456. }
  457. // rplWhoReply returns the WHO reply between one user and another channel/user.
  458. // <channel> <user> <host> <server> <nick> ( "H" / "G" ) ["*"] [ ( "@" / "+" ) ]
  459. // :<hopcount> <real name>
  460. func (client *Client) rplWhoReply(channel *Channel, target *Client, rb *ResponseBuffer) {
  461. channelName := "*"
  462. flags := ""
  463. if target.Away() {
  464. flags = "G"
  465. } else {
  466. flags = "H"
  467. }
  468. if target.HasMode(modes.Operator) {
  469. flags += "*"
  470. }
  471. if channel != nil {
  472. // TODO is this right?
  473. flags += channel.ClientPrefixes(target, rb.session.capabilities.Has(caps.MultiPrefix))
  474. channelName = channel.name
  475. }
  476. details := target.Details()
  477. // hardcode a hopcount of 0 for now
  478. rb.Add(nil, client.server.name, RPL_WHOREPLY, client.Nick(), channelName, details.username, details.hostname, client.server.name, details.nick, flags, "0 "+details.realname)
  479. }
  480. // rehash reloads the config and applies the changes from the config file.
  481. func (server *Server) rehash() error {
  482. server.logger.Debug("server", "Starting rehash")
  483. // only let one REHASH go on at a time
  484. server.rehashMutex.Lock()
  485. defer server.rehashMutex.Unlock()
  486. server.logger.Debug("server", "Got rehash lock")
  487. config, err := LoadConfig(server.configFilename)
  488. if err != nil {
  489. return fmt.Errorf("Error loading config file config: %s", err.Error())
  490. }
  491. err = server.applyConfig(config, false)
  492. if err != nil {
  493. return fmt.Errorf("Error applying config changes: %s", err.Error())
  494. }
  495. return nil
  496. }
  497. func (server *Server) applyConfig(config *Config, initial bool) (err error) {
  498. if initial {
  499. server.configFilename = config.Filename
  500. server.name = config.Server.Name
  501. server.nameCasefolded = config.Server.nameCasefolded
  502. } else {
  503. // enforce configs that can't be changed after launch:
  504. currentLimits := server.Config().Limits
  505. if currentLimits.LineLen.Rest != config.Limits.LineLen.Rest {
  506. return fmt.Errorf("Maximum line length (linelen) cannot be changed after launching the server, rehash aborted")
  507. } else if server.name != config.Server.Name {
  508. return fmt.Errorf("Server name cannot be changed after launching the server, rehash aborted")
  509. } else if server.Config().Datastore.Path != config.Datastore.Path {
  510. return fmt.Errorf("Datastore path cannot be changed after launching the server, rehash aborted")
  511. }
  512. }
  513. // sanity checks complete, start modifying server state
  514. server.logger.Info("server", "Using config file", server.configFilename)
  515. oldConfig := server.Config()
  516. // first, reload config sections for functionality implemented in subpackages:
  517. err = server.connectionLimiter.ApplyConfig(config.Server.ConnectionLimiter)
  518. if err != nil {
  519. return err
  520. }
  521. err = server.connectionThrottler.ApplyConfig(config.Server.ConnectionThrottler)
  522. if err != nil {
  523. return err
  524. }
  525. tlConf := &config.Server.TorListeners
  526. server.torLimiter.Configure(tlConf.MaxConnections, tlConf.ThrottleDuration, tlConf.MaxConnectionsPerDuration)
  527. // reload logging config
  528. wasLoggingRawIO := !initial && server.logger.IsLoggingRawIO()
  529. err = server.logger.ApplyConfig(config.Logging)
  530. if err != nil {
  531. return err
  532. }
  533. nowLoggingRawIO := server.logger.IsLoggingRawIO()
  534. // notify existing clients if raw i/o logging was enabled by a rehash
  535. sendRawOutputNotice := !wasLoggingRawIO && nowLoggingRawIO
  536. // setup new and removed caps
  537. addedCaps := caps.NewSet()
  538. removedCaps := caps.NewSet()
  539. updatedCaps := caps.NewSet()
  540. // Translations
  541. server.logger.Debug("server", "Regenerating HELP indexes for new languages")
  542. server.helpIndexManager.GenerateIndices(config.languageManager)
  543. currentLanguageValue, _ := CapValues.Get(caps.Languages)
  544. newLanguageValue := config.languageManager.CapValue()
  545. if currentLanguageValue != newLanguageValue {
  546. updatedCaps.Add(caps.Languages)
  547. CapValues.Set(caps.Languages, newLanguageValue)
  548. }
  549. // SASL
  550. authPreviouslyEnabled := oldConfig != nil && oldConfig.Accounts.AuthenticationEnabled
  551. if config.Accounts.AuthenticationEnabled && (oldConfig == nil || !authPreviouslyEnabled) {
  552. // enabling SASL
  553. SupportedCapabilities.Enable(caps.SASL)
  554. CapValues.Set(caps.SASL, "PLAIN,EXTERNAL")
  555. addedCaps.Add(caps.SASL)
  556. } else if !config.Accounts.AuthenticationEnabled && (oldConfig == nil || authPreviouslyEnabled) {
  557. // disabling SASL
  558. SupportedCapabilities.Disable(caps.SASL)
  559. removedCaps.Add(caps.SASL)
  560. }
  561. nickReservationPreviouslyDisabled := oldConfig != nil && !oldConfig.Accounts.NickReservation.Enabled
  562. nickReservationNowEnabled := config.Accounts.NickReservation.Enabled
  563. if nickReservationPreviouslyDisabled && nickReservationNowEnabled {
  564. server.accounts.buildNickToAccountIndex()
  565. }
  566. hsPreviouslyDisabled := oldConfig != nil && !oldConfig.Accounts.VHosts.Enabled
  567. hsNowEnabled := config.Accounts.VHosts.Enabled
  568. if hsPreviouslyDisabled && hsNowEnabled {
  569. server.accounts.initVHostRequestQueue()
  570. }
  571. chanRegPreviouslyDisabled := oldConfig != nil && !oldConfig.Channels.Registration.Enabled
  572. chanRegNowEnabled := config.Channels.Registration.Enabled
  573. if chanRegPreviouslyDisabled && chanRegNowEnabled {
  574. server.channels.loadRegisteredChannels()
  575. }
  576. // MaxLine
  577. if config.Limits.LineLen.Rest != 512 {
  578. SupportedCapabilities.Enable(caps.MaxLine)
  579. value := fmt.Sprintf("%d", config.Limits.LineLen.Rest)
  580. CapValues.Set(caps.MaxLine, value)
  581. } else {
  582. SupportedCapabilities.Disable(caps.MaxLine)
  583. }
  584. // STS
  585. stsPreviouslyEnabled := oldConfig != nil && oldConfig.Server.STS.Enabled
  586. stsValue := config.Server.STS.Value()
  587. stsDisabledByRehash := false
  588. stsCurrentCapValue, _ := CapValues.Get(caps.STS)
  589. server.logger.Debug("server", "STS Vals", stsCurrentCapValue, stsValue, fmt.Sprintf("server[%v] config[%v]", stsPreviouslyEnabled, config.Server.STS.Enabled))
  590. if config.Server.STS.Enabled {
  591. // enabling STS
  592. SupportedCapabilities.Enable(caps.STS)
  593. if !stsPreviouslyEnabled {
  594. addedCaps.Add(caps.STS)
  595. CapValues.Set(caps.STS, stsValue)
  596. } else if stsValue != stsCurrentCapValue {
  597. // STS policy updated
  598. CapValues.Set(caps.STS, stsValue)
  599. updatedCaps.Add(caps.STS)
  600. }
  601. } else {
  602. // disabling STS
  603. SupportedCapabilities.Disable(caps.STS)
  604. if stsPreviouslyEnabled {
  605. removedCaps.Add(caps.STS)
  606. stsDisabledByRehash = true
  607. }
  608. }
  609. // resize history buffers as needed
  610. if oldConfig != nil && oldConfig.History != config.History {
  611. for _, channel := range server.channels.Channels() {
  612. channel.history.Resize(config.History.ChannelLength, config.History.AutoresizeWindow)
  613. }
  614. for _, client := range server.clients.AllClients() {
  615. client.history.Resize(config.History.ClientLength, config.History.AutoresizeWindow)
  616. }
  617. }
  618. // burst new and removed caps
  619. var capBurstSessions []*Session
  620. added := make(map[caps.Version]string)
  621. var removed string
  622. // updated caps get DEL'd and then NEW'd
  623. // so, we can just add updated ones to both removed and added lists here and they'll be correctly handled
  624. server.logger.Debug("server", "Updated Caps", updatedCaps.String(caps.Cap301, CapValues))
  625. addedCaps.Union(updatedCaps)
  626. removedCaps.Union(updatedCaps)
  627. if !addedCaps.Empty() || !removedCaps.Empty() {
  628. capBurstSessions = server.clients.AllWithCapsNotify()
  629. added[caps.Cap301] = addedCaps.String(caps.Cap301, CapValues)
  630. added[caps.Cap302] = addedCaps.String(caps.Cap302, CapValues)
  631. // removed never has values, so we leave it as Cap301
  632. removed = removedCaps.String(caps.Cap301, CapValues)
  633. }
  634. for _, sSession := range capBurstSessions {
  635. if stsDisabledByRehash {
  636. // remove STS policy
  637. //TODO(dan): this is an ugly hack. we can write this better.
  638. stsPolicy := "sts=duration=0"
  639. if !addedCaps.Empty() {
  640. added[caps.Cap302] = added[caps.Cap302] + " " + stsPolicy
  641. } else {
  642. addedCaps.Enable(caps.STS)
  643. added[caps.Cap302] = stsPolicy
  644. }
  645. }
  646. // DEL caps and then send NEW ones so that updated caps get removed/added correctly
  647. if !removedCaps.Empty() {
  648. sSession.Send(nil, server.name, "CAP", sSession.client.Nick(), "DEL", removed)
  649. }
  650. if !addedCaps.Empty() {
  651. sSession.Send(nil, server.name, "CAP", sSession.client.Nick(), "NEW", added[sSession.capVersion])
  652. }
  653. }
  654. // save a pointer to the new config
  655. server.SetConfig(config)
  656. server.logger.Info("server", "Using datastore", config.Datastore.Path)
  657. if initial {
  658. if err := server.loadDatastore(config); err != nil {
  659. return err
  660. }
  661. }
  662. server.setupPprofListener(config)
  663. // set RPL_ISUPPORT
  664. var newISupportReplies [][]string
  665. if oldConfig != nil {
  666. newISupportReplies = oldConfig.Server.isupport.GetDifference(&config.Server.isupport)
  667. }
  668. // we are now open for business
  669. err = server.setupListeners(config)
  670. if !initial {
  671. // push new info to all of our clients
  672. for _, sClient := range server.clients.AllClients() {
  673. for _, tokenline := range newISupportReplies {
  674. sClient.Send(nil, server.name, RPL_ISUPPORT, append([]string{sClient.nick}, tokenline...)...)
  675. }
  676. if sendRawOutputNotice {
  677. sClient.Notice(sClient.t("This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
  678. }
  679. if !oldConfig.Accounts.NickReservation.Enabled && config.Accounts.NickReservation.Enabled {
  680. sClient.nickTimer.Initialize(sClient)
  681. sClient.nickTimer.Touch(nil)
  682. } else if oldConfig.Accounts.NickReservation.Enabled && !config.Accounts.NickReservation.Enabled {
  683. sClient.nickTimer.Stop()
  684. }
  685. }
  686. }
  687. return err
  688. }
  689. func (server *Server) setupPprofListener(config *Config) {
  690. pprofListener := ""
  691. if config.Debug.PprofListener != nil {
  692. pprofListener = *config.Debug.PprofListener
  693. }
  694. if server.pprofServer != nil {
  695. if pprofListener == "" || (pprofListener != server.pprofServer.Addr) {
  696. server.logger.Info("server", "Stopping pprof listener", server.pprofServer.Addr)
  697. server.pprofServer.Close()
  698. server.pprofServer = nil
  699. }
  700. }
  701. if pprofListener != "" && server.pprofServer == nil {
  702. ps := http.Server{
  703. Addr: pprofListener,
  704. }
  705. go func() {
  706. if err := ps.ListenAndServe(); err != nil {
  707. server.logger.Error("server", "pprof listener failed", err.Error())
  708. }
  709. }()
  710. server.pprofServer = &ps
  711. server.logger.Info("server", "Started pprof listener", server.pprofServer.Addr)
  712. }
  713. }
  714. func (config *Config) loadMOTD() (err error) {
  715. if config.Server.MOTD != "" {
  716. file, err := os.Open(config.Server.MOTD)
  717. if err == nil {
  718. defer file.Close()
  719. reader := bufio.NewReader(file)
  720. for {
  721. line, err := reader.ReadString('\n')
  722. if err != nil {
  723. break
  724. }
  725. line = strings.TrimRight(line, "\r\n")
  726. if config.Server.MOTDFormatting {
  727. line = ircfmt.Unescape(line)
  728. }
  729. // "- " is the required prefix for MOTD, we just add it here to make
  730. // bursting it out to clients easier
  731. line = fmt.Sprintf("- %s", line)
  732. config.Server.motdLines = append(config.Server.motdLines, line)
  733. }
  734. }
  735. }
  736. return
  737. }
  738. func (server *Server) loadDatastore(config *Config) error {
  739. // open the datastore and load server state for which it (rather than config)
  740. // is the source of truth
  741. _, err := os.Stat(config.Datastore.Path)
  742. if os.IsNotExist(err) {
  743. server.logger.Warning("server", "database does not exist, creating it", config.Datastore.Path)
  744. err = initializeDB(config.Datastore.Path)
  745. if err != nil {
  746. return err
  747. }
  748. }
  749. db, err := OpenDatabase(config)
  750. if err == nil {
  751. server.store = db
  752. } else {
  753. return fmt.Errorf("Failed to open datastore: %s", err.Error())
  754. }
  755. // load *lines (from the datastores)
  756. server.logger.Debug("server", "Loading D/Klines")
  757. server.loadDLines()
  758. server.loadKLines()
  759. server.channelRegistry.Initialize(server)
  760. server.channels.Initialize(server)
  761. server.accounts.Initialize(server)
  762. return nil
  763. }
  764. func (server *Server) setupListeners(config *Config) (err error) {
  765. logListener := func(addr string, config listenerConfig) {
  766. server.logger.Info("listeners",
  767. fmt.Sprintf("now listening on %s, tls=%t, tor=%t.", addr, (config.TLSConfig != nil), config.IsTor),
  768. )
  769. }
  770. // update or destroy all existing listeners
  771. for addr := range server.listeners {
  772. currentListener := server.listeners[addr]
  773. newConfig, stillConfigured := config.Server.trueListeners[addr]
  774. currentListener.Lock()
  775. currentListener.shouldStop = !stillConfigured
  776. currentListener.config = newConfig
  777. currentListener.Unlock()
  778. if stillConfigured {
  779. logListener(addr, newConfig)
  780. } else {
  781. // tell the listener it should stop by interrupting its Accept() call:
  782. currentListener.listener.Close()
  783. delete(server.listeners, addr)
  784. server.logger.Info("listeners", fmt.Sprintf("stopped listening on %s.", addr))
  785. }
  786. }
  787. // create new listeners that were not previously configured
  788. numTlsListeners := 0
  789. hasStandardTlsListener := false
  790. for newAddr, newConfig := range config.Server.trueListeners {
  791. if newConfig.TLSConfig != nil {
  792. numTlsListeners += 1
  793. if strings.HasSuffix(newAddr, ":6697") {
  794. hasStandardTlsListener = true
  795. }
  796. }
  797. _, exists := server.listeners[newAddr]
  798. if !exists {
  799. // make new listener
  800. listener, listenerErr := server.createListener(newAddr, newConfig, config.Server.UnixBindMode)
  801. if listenerErr != nil {
  802. server.logger.Error("server", "couldn't listen on", newAddr, listenerErr.Error())
  803. err = listenerErr
  804. continue
  805. }
  806. server.listeners[newAddr] = listener
  807. logListener(newAddr, newConfig)
  808. }
  809. }
  810. if numTlsListeners == 0 {
  811. server.logger.Warning("server", "You are not exposing an SSL/TLS listening port. You should expose at least one port (typically 6697) to accept TLS connections")
  812. }
  813. if !hasStandardTlsListener {
  814. server.logger.Warning("server", "Port 6697 is the standard TLS port for IRC. You should (also) expose port 6697 as a TLS port to ensure clients can connect securely")
  815. }
  816. return
  817. }
  818. // elistMatcher takes and matches ELIST conditions
  819. type elistMatcher struct {
  820. MinClientsActive bool
  821. MinClients int
  822. MaxClientsActive bool
  823. MaxClients int
  824. }
  825. // Matches checks whether the given channel matches our matches.
  826. func (matcher *elistMatcher) Matches(channel *Channel) bool {
  827. if matcher.MinClientsActive {
  828. if len(channel.Members()) < matcher.MinClients {
  829. return false
  830. }
  831. }
  832. if matcher.MaxClientsActive {
  833. if len(channel.Members()) < len(channel.members) {
  834. return false
  835. }
  836. }
  837. return true
  838. }
  839. // RplList returns the RPL_LIST numeric for the given channel.
  840. func (target *Client) RplList(channel *Channel, rb *ResponseBuffer) {
  841. // get the correct number of channel members
  842. var memberCount int
  843. if target.HasMode(modes.Operator) || channel.hasClient(target) {
  844. memberCount = len(channel.Members())
  845. } else {
  846. for _, member := range channel.Members() {
  847. if !member.HasMode(modes.Invisible) {
  848. memberCount++
  849. }
  850. }
  851. }
  852. rb.Add(nil, target.server.name, RPL_LIST, target.nick, channel.name, strconv.Itoa(memberCount), channel.topic)
  853. }
  854. var (
  855. infoString1 = strings.Split(` ▄▄▄ ▄▄▄· ▄▄ • ▐ ▄
  856. ▪ ▀▄ █·▐█ ▀█ ▐█ ▀ ▪▪ •█▌▐█▪
  857. ▄█▀▄ ▐▀▀▄ ▄█▀▀█ ▄█ ▀█▄ ▄█▀▄▪▐█▐▐▌ ▄█▀▄
  858. ▐█▌.▐▌▐█•█▌▐█ ▪▐▌▐█▄▪▐█▐█▌ ▐▌██▐█▌▐█▌.▐▌
  859. ▀█▄▀▪.▀ ▀ ▀ ▀ ·▀▀▀▀ ▀█▄▀ ▀▀ █▪ ▀█▄▀▪
  860. https://oragono.io/
  861. https://github.com/oragono/oragono
  862. https://crowdin.com/project/oragono
  863. `, "\n")
  864. infoString2 = strings.Split(` Daniel Oakley, DanielOaks, <daniel@danieloaks.net>
  865. Shivaram Lingamneni, slingamn, <slingamn@cs.stanford.edu>
  866. `, "\n")
  867. infoString3 = strings.Split(` 3onyc
  868. Edmund Huber
  869. Euan Kemp (euank)
  870. Jeremy Latt
  871. Martin Lindhe (martinlindhe)
  872. Roberto Besser (besser)
  873. Robin Burchell (rburchell)
  874. Sean Enck (enckse)
  875. soul9
  876. Vegax
  877. `, "\n")
  878. )