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.

server.go 33KB

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