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.

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