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

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