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

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