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

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