您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

server.go 40KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
  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. "encoding/base64"
  10. "fmt"
  11. "log"
  12. "math/rand"
  13. "net"
  14. "net/http"
  15. _ "net/http/pprof"
  16. "os"
  17. "os/signal"
  18. "strconv"
  19. "strings"
  20. "sync"
  21. "syscall"
  22. "time"
  23. "github.com/goshuirc/irc-go/ircfmt"
  24. "github.com/goshuirc/irc-go/ircmsg"
  25. "github.com/oragono/oragono/irc/caps"
  26. "github.com/oragono/oragono/irc/connection_limits"
  27. "github.com/oragono/oragono/irc/isupport"
  28. "github.com/oragono/oragono/irc/languages"
  29. "github.com/oragono/oragono/irc/logger"
  30. "github.com/oragono/oragono/irc/modes"
  31. "github.com/oragono/oragono/irc/passwd"
  32. "github.com/oragono/oragono/irc/sno"
  33. "github.com/oragono/oragono/irc/utils"
  34. "github.com/tidwall/buntdb"
  35. )
  36. var (
  37. // common error line to sub values into
  38. errorMsg, _ = (&[]ircmsg.IrcMessage{ircmsg.MakeMessage(nil, "", "ERROR", "%s ")}[0]).Line()
  39. // common error responses
  40. couldNotParseIPMsg, _ = (&[]ircmsg.IrcMessage{ircmsg.MakeMessage(nil, "", "ERROR", "Unable to parse your IP address")}[0]).Line()
  41. // supportedUserModesString acts as a cache for when we introduce users
  42. supportedUserModesString = modes.SupportedUserModes.String()
  43. // supportedChannelModesString acts as a cache for when we introduce users
  44. supportedChannelModesString = modes.SupportedChannelModes.String()
  45. // SupportedCapabilities are the caps we advertise.
  46. // MaxLine, SASL and STS are set during server startup.
  47. 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.UserhostInNames)
  48. // CapValues are the actual values we advertise to v3.2 clients.
  49. // actual values are set during server startup.
  50. CapValues = caps.NewValues()
  51. )
  52. // Limits holds the maximum limits for various things such as topic lengths.
  53. type Limits struct {
  54. AwayLen int
  55. ChannelLen int
  56. KickLen int
  57. MonitorEntries int
  58. NickLen int
  59. TopicLen int
  60. ChanListModes int
  61. LineLen LineLenLimits
  62. }
  63. // LineLenLimits holds the maximum limits for IRC lines.
  64. type LineLenLimits struct {
  65. Tags int
  66. Rest int
  67. }
  68. // ListenerWrapper wraps a listener so it can be safely reconfigured or stopped
  69. type ListenerWrapper struct {
  70. listener net.Listener
  71. tlsConfig *tls.Config
  72. shouldStop bool
  73. // protects atomic update of tlsConfig and shouldStop:
  74. configMutex sync.Mutex // tier 1
  75. }
  76. // Server is the main Oragono server.
  77. type Server struct {
  78. accounts *AccountManager
  79. batches *BatchManager
  80. channels *ChannelManager
  81. channelRegistry *ChannelRegistry
  82. checkIdent bool
  83. clients *ClientManager
  84. config *Config
  85. configFilename string
  86. configurableStateMutex sync.RWMutex // tier 1; generic protection for server state modified by rehash()
  87. connectionLimiter *connection_limits.Limiter
  88. connectionThrottler *connection_limits.Throttler
  89. ctime time.Time
  90. defaultChannelModes modes.Modes
  91. dlines *DLineManager
  92. loggingRawIO bool
  93. isupport *isupport.List
  94. klines *KLineManager
  95. languages *languages.Manager
  96. limits Limits
  97. listeners map[string]*ListenerWrapper
  98. logger *logger.Manager
  99. maxSendQBytes uint32
  100. monitorManager *MonitorManager
  101. motdLines []string
  102. name string
  103. nameCasefolded string
  104. networkName string
  105. operators map[string]*Oper
  106. operclasses map[string]*OperClass
  107. password []byte
  108. passwords *passwd.SaltedManager
  109. recoverFromErrors bool
  110. rehashMutex sync.Mutex // tier 4
  111. rehashSignal chan os.Signal
  112. pprofServer *http.Server
  113. proxyAllowedFrom []string
  114. signals chan os.Signal
  115. snomasks *SnoManager
  116. store *buntdb.DB
  117. stsEnabled bool
  118. webirc []webircConfig
  119. whoWas *WhoWasList
  120. stats *Stats
  121. semaphores *ServerSemaphores
  122. }
  123. var (
  124. // ServerExitSignals are the signals the server will exit on.
  125. ServerExitSignals = []os.Signal{
  126. syscall.SIGINT,
  127. syscall.SIGTERM,
  128. syscall.SIGQUIT,
  129. }
  130. )
  131. type clientConn struct {
  132. Conn net.Conn
  133. IsTLS bool
  134. }
  135. // NewServer returns a new Oragono server.
  136. func NewServer(config *Config, logger *logger.Manager) (*Server, error) {
  137. // initialize data structures
  138. server := &Server{
  139. batches: NewBatchManager(),
  140. channels: NewChannelManager(),
  141. clients: NewClientManager(),
  142. connectionLimiter: connection_limits.NewLimiter(),
  143. connectionThrottler: connection_limits.NewThrottler(),
  144. languages: languages.NewManager(config.Languages.Default, config.Languages.Data),
  145. listeners: make(map[string]*ListenerWrapper),
  146. logger: logger,
  147. monitorManager: NewMonitorManager(),
  148. rehashSignal: make(chan os.Signal, 1),
  149. signals: make(chan os.Signal, len(ServerExitSignals)),
  150. snomasks: NewSnoManager(),
  151. whoWas: NewWhoWasList(config.Limits.WhowasEntries),
  152. stats: NewStats(),
  153. semaphores: NewServerSemaphores(),
  154. }
  155. if err := server.applyConfig(config, true); err != nil {
  156. return nil, err
  157. }
  158. // generate help info
  159. if err := GenerateHelpIndices(server.languages); err != nil {
  160. return nil, err
  161. }
  162. // confirm help entries for ChanServ exist.
  163. // this forces people to write help entries for every single CS command.
  164. for commandName, commandInfo := range chanservCommands {
  165. if commandInfo.help == "" || commandInfo.helpShort == "" {
  166. return nil, fmt.Errorf("Help entry does not exist for ChanServ command %s", commandName)
  167. }
  168. }
  169. // confirm help entries for NickServ exist.
  170. // this forces people to write help entries for every single NS command.
  171. for commandName, commandInfo := range nickservCommands {
  172. if commandInfo.help == "" || commandInfo.helpShort == "" {
  173. return nil, fmt.Errorf("Help entry does not exist for NickServ command %s", commandName)
  174. }
  175. }
  176. // Attempt to clean up when receiving these signals.
  177. signal.Notify(server.signals, ServerExitSignals...)
  178. signal.Notify(server.rehashSignal, syscall.SIGHUP)
  179. return server, nil
  180. }
  181. // setISupport sets up our RPL_ISUPPORT reply.
  182. func (server *Server) setISupport() {
  183. maxTargetsString := strconv.Itoa(maxTargets)
  184. server.configurableStateMutex.RLock()
  185. // add RPL_ISUPPORT tokens
  186. isupport := isupport.NewList()
  187. isupport.Add("AWAYLEN", strconv.Itoa(server.limits.AwayLen))
  188. isupport.Add("CASEMAPPING", "ascii")
  189. 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()}, ","))
  190. isupport.Add("CHANNELLEN", strconv.Itoa(server.limits.ChannelLen))
  191. isupport.Add("CHANTYPES", "#")
  192. isupport.Add("ELIST", "U")
  193. isupport.Add("EXCEPTS", "")
  194. isupport.Add("INVEX", "")
  195. isupport.Add("KICKLEN", strconv.Itoa(server.limits.KickLen))
  196. isupport.Add("MAXLIST", fmt.Sprintf("beI:%s", strconv.Itoa(server.limits.ChanListModes)))
  197. isupport.Add("MAXTARGETS", maxTargetsString)
  198. isupport.Add("MODES", "")
  199. isupport.Add("MONITOR", strconv.Itoa(server.limits.MonitorEntries))
  200. isupport.Add("NETWORK", server.networkName)
  201. isupport.Add("NICKLEN", strconv.Itoa(server.limits.NickLen))
  202. isupport.Add("PREFIX", "(qaohv)~&@%+")
  203. isupport.Add("RPCHAN", "E")
  204. isupport.Add("RPUSER", "E")
  205. isupport.Add("STATUSMSG", "~&@%+")
  206. 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))
  207. isupport.Add("TOPICLEN", strconv.Itoa(server.limits.TopicLen))
  208. isupport.Add("UTF8MAPPING", casemappingName)
  209. // account registration
  210. if server.config.Accounts.Registration.Enabled {
  211. // 'none' isn't shown in the REGCALLBACKS vars
  212. var enabledCallbacks []string
  213. for _, name := range server.config.Accounts.Registration.EnabledCallbacks {
  214. if name != "*" {
  215. enabledCallbacks = append(enabledCallbacks, name)
  216. }
  217. }
  218. isupport.Add("ACCCOMMANDS", "CREATE,VERIFY")
  219. isupport.Add("REGCALLBACKS", strings.Join(enabledCallbacks, ","))
  220. isupport.Add("REGCREDTYPES", "passphrase,certfp")
  221. }
  222. server.configurableStateMutex.RUnlock()
  223. isupport.RegenerateCachedReply()
  224. server.configurableStateMutex.Lock()
  225. server.isupport = isupport
  226. server.configurableStateMutex.Unlock()
  227. }
  228. func loadChannelList(channel *Channel, list string, maskMode modes.Mode) {
  229. if list == "" {
  230. return
  231. }
  232. channel.lists[maskMode].AddAll(strings.Split(list, " "))
  233. }
  234. // Shutdown shuts down the server.
  235. func (server *Server) Shutdown() {
  236. //TODO(dan): Make sure we disallow new nicks
  237. for _, client := range server.clients.AllClients() {
  238. client.Notice("Server is shutting down")
  239. }
  240. if err := server.store.Close(); err != nil {
  241. server.logger.Error("shutdown", fmt.Sprintln("Could not close datastore:", err))
  242. }
  243. }
  244. // Run starts the server.
  245. func (server *Server) Run() {
  246. // defer closing db/store
  247. defer server.store.Close()
  248. for {
  249. select {
  250. case <-server.signals:
  251. server.Shutdown()
  252. return
  253. case <-server.rehashSignal:
  254. go func() {
  255. server.logger.Info("rehash", "Rehashing due to SIGHUP")
  256. err := server.rehash()
  257. if err != nil {
  258. server.logger.Error("rehash", fmt.Sprintln("Failed to rehash:", err.Error()))
  259. }
  260. }()
  261. }
  262. }
  263. }
  264. func (server *Server) acceptClient(conn clientConn) {
  265. // check IP address
  266. ipaddr := utils.AddrToIP(conn.Conn.RemoteAddr())
  267. if ipaddr != nil {
  268. isBanned, banMsg := server.checkBans(ipaddr)
  269. if isBanned {
  270. // 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
  271. conn.Conn.Write([]byte(fmt.Sprintf(errorMsg, banMsg)))
  272. conn.Conn.Close()
  273. return
  274. }
  275. }
  276. server.logger.Debug("localconnect-ip", fmt.Sprintf("Client connecting from %v", ipaddr))
  277. // prolly don't need to alert snomasks on this, only on connection reg
  278. NewClient(server, conn.Conn, conn.IsTLS)
  279. }
  280. func (server *Server) checkBans(ipaddr net.IP) (banned bool, message string) {
  281. // check DLINEs
  282. isBanned, info := server.dlines.CheckIP(ipaddr)
  283. if isBanned {
  284. server.logger.Info("localconnect-ip", fmt.Sprintf("Client from %v rejected by d-line", ipaddr))
  285. return true, info.BanMessage("You are banned from this server (%s)")
  286. }
  287. // check connection limits
  288. err := server.connectionLimiter.AddClient(ipaddr, false)
  289. if err != nil {
  290. // too many connections from one client, tell the client and close the connection
  291. server.logger.Info("localconnect-ip", fmt.Sprintf("Client from %v rejected for connection limit", ipaddr))
  292. return true, "Too many clients from your network"
  293. }
  294. // check connection throttle
  295. err = server.connectionThrottler.AddClient(ipaddr)
  296. if err != nil {
  297. // too many connections too quickly from client, tell them and close the connection
  298. duration := server.connectionThrottler.BanDuration()
  299. length := &IPRestrictTime{
  300. Duration: duration,
  301. Expires: time.Now().Add(duration),
  302. }
  303. server.dlines.AddIP(ipaddr, length, server.connectionThrottler.BanMessage(), "Exceeded automated connection throttle", "auto.connection.throttler")
  304. // they're DLINE'd for 15 minutes or whatever, so we can reset the connection throttle now,
  305. // and once their temporary DLINE is finished they can fill up the throttler again
  306. server.connectionThrottler.ResetFor(ipaddr)
  307. // 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
  308. server.logger.Info(
  309. "localconnect-ip",
  310. fmt.Sprintf("Client from %v exceeded connection throttle, d-lining for %v", ipaddr, duration))
  311. return true, server.connectionThrottler.BanMessage()
  312. }
  313. return false, ""
  314. }
  315. //
  316. // IRC protocol listeners
  317. //
  318. // createListener starts the given listeners.
  319. func (server *Server) createListener(addr string, tlsConfig *tls.Config) *ListenerWrapper {
  320. // make listener
  321. var listener net.Listener
  322. var err error
  323. addr = strings.TrimPrefix(addr, "unix:")
  324. if strings.HasPrefix(addr, "/") {
  325. // https://stackoverflow.com/a/34881585
  326. os.Remove(addr)
  327. listener, err = net.Listen("unix", addr)
  328. } else {
  329. listener, err = net.Listen("tcp", addr)
  330. }
  331. if err != nil {
  332. log.Fatal(server, "listen error: ", err)
  333. }
  334. // throw our details to the server so we can be modified/killed later
  335. wrapper := ListenerWrapper{
  336. listener: listener,
  337. tlsConfig: tlsConfig,
  338. shouldStop: false,
  339. }
  340. var shouldStop bool
  341. // setup accept goroutine
  342. go func() {
  343. for {
  344. conn, err := listener.Accept()
  345. // synchronously access config data:
  346. // whether TLS is enabled and whether we should stop listening
  347. wrapper.configMutex.Lock()
  348. shouldStop = wrapper.shouldStop
  349. tlsConfig = wrapper.tlsConfig
  350. wrapper.configMutex.Unlock()
  351. if err == nil {
  352. if tlsConfig != nil {
  353. conn = tls.Server(conn, tlsConfig)
  354. }
  355. newConn := clientConn{
  356. Conn: conn,
  357. IsTLS: tlsConfig != nil,
  358. }
  359. // hand off the connection
  360. go server.acceptClient(newConn)
  361. }
  362. if shouldStop {
  363. listener.Close()
  364. return
  365. }
  366. }
  367. }()
  368. return &wrapper
  369. }
  370. // generateMessageID returns a network-unique message ID.
  371. func (server *Server) generateMessageID() string {
  372. // we don't need the full like 30 chars since the unixnano below handles
  373. // most of our uniqueness requirements, so just truncate at 5
  374. lastbit := strconv.FormatInt(rand.Int63(), 36)
  375. if 5 < len(lastbit) {
  376. lastbit = lastbit[:4]
  377. }
  378. return fmt.Sprintf("%s%s", strconv.FormatInt(time.Now().UTC().UnixNano(), 36), lastbit)
  379. }
  380. //
  381. // server functionality
  382. //
  383. func (server *Server) tryRegister(c *Client) {
  384. if c.Registered() {
  385. return
  386. }
  387. preregNick := c.PreregNick()
  388. if preregNick == "" || !c.HasUsername() || c.capState == caps.NegotiatingState {
  389. return
  390. }
  391. // client MUST send PASS (or AUTHENTICATE, if skip-server-password is set)
  392. // before completing the other registration commands
  393. if !c.Authorized() {
  394. c.Quit(c.t("Bad password"))
  395. c.destroy(false)
  396. return
  397. }
  398. rb := NewResponseBuffer(c)
  399. nickAssigned := performNickChange(server, c, c, preregNick, rb)
  400. rb.Send()
  401. if !nickAssigned {
  402. c.SetPreregNick("")
  403. return
  404. }
  405. // check KLINEs
  406. isBanned, info := server.klines.CheckMasks(c.AllNickmasks()...)
  407. if isBanned {
  408. reason := info.Reason
  409. if info.Time != nil {
  410. reason += fmt.Sprintf(" [%s]", info.Time.Duration.String())
  411. }
  412. c.Quit(fmt.Sprintf(c.t("You are banned from this server (%s)"), reason))
  413. c.destroy(false)
  414. return
  415. }
  416. // count new user in statistics
  417. server.stats.ChangeTotal(1)
  418. // continue registration
  419. server.logger.Debug("localconnect", fmt.Sprintf("Client connected [%s] [u:%s] [r:%s]", c.nick, c.username, c.realname))
  420. 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))
  421. c.Register()
  422. // send welcome text
  423. //NOTE(dan): we specifically use the NICK here instead of the nickmask
  424. // see http://modern.ircdocs.horse/#rplwelcome-001 for details on why we avoid using the nickmask
  425. c.Send(nil, server.name, RPL_WELCOME, c.nick, fmt.Sprintf(c.t("Welcome to the Internet Relay Network %s"), c.nick))
  426. 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))
  427. c.Send(nil, server.name, RPL_CREATED, c.nick, fmt.Sprintf(c.t("This server was created %s"), server.ctime.Format(time.RFC1123)))
  428. //TODO(dan): Look at adding last optional [<channel modes with a parameter>] parameter
  429. c.Send(nil, server.name, RPL_MYINFO, c.nick, server.name, Ver, supportedUserModesString, supportedChannelModesString)
  430. rb = NewResponseBuffer(c)
  431. c.RplISupport(rb)
  432. server.MOTD(c, rb)
  433. rb.Send()
  434. modestring := c.ModeString()
  435. if modestring != "+" {
  436. c.Send(nil, c.nickMaskString, RPL_UMODEIS, c.nick, c.ModeString())
  437. }
  438. if server.logger.IsLoggingRawIO() {
  439. 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."))
  440. }
  441. // if resumed, send fake channel joins
  442. if c.resumeDetails != nil {
  443. for _, name := range c.resumeDetails.SendFakeJoinsFor {
  444. channel := server.channels.Get(name)
  445. if channel == nil {
  446. continue
  447. }
  448. if c.capabilities.Has(caps.ExtendedJoin) {
  449. c.Send(nil, c.nickMaskString, "JOIN", channel.name, c.AccountName(), c.realname)
  450. } else {
  451. c.Send(nil, c.nickMaskString, "JOIN", channel.name)
  452. }
  453. // reuse the last rb
  454. channel.SendTopic(c, rb)
  455. channel.Names(c, rb)
  456. rb.Send()
  457. // construct and send fake modestring if necessary
  458. c.stateMutex.RLock()
  459. myModes := channel.members[c]
  460. c.stateMutex.RUnlock()
  461. if myModes == nil {
  462. continue
  463. }
  464. oldModes := myModes.String()
  465. if 0 < len(oldModes) {
  466. params := []string{channel.name, "+" + oldModes}
  467. for range oldModes {
  468. params = append(params, c.nick)
  469. }
  470. c.Send(nil, server.name, "MODE", params...)
  471. }
  472. }
  473. }
  474. }
  475. // t returns the translated version of the given string, based on the languages configured by the client.
  476. func (client *Client) t(originalString string) string {
  477. // grab this mutex to protect client.languages
  478. client.stateMutex.RLock()
  479. defer client.stateMutex.RUnlock()
  480. return client.server.languages.Translate(client.languages, originalString)
  481. }
  482. // MOTD serves the Message of the Day.
  483. func (server *Server) MOTD(client *Client, rb *ResponseBuffer) {
  484. server.configurableStateMutex.RLock()
  485. motdLines := server.motdLines
  486. server.configurableStateMutex.RUnlock()
  487. if len(motdLines) < 1 {
  488. rb.Add(nil, server.name, ERR_NOMOTD, client.nick, client.t("MOTD File is missing"))
  489. return
  490. }
  491. rb.Add(nil, server.name, RPL_MOTDSTART, client.nick, fmt.Sprintf(client.t("- %s Message of the day - "), server.name))
  492. for _, line := range motdLines {
  493. rb.Add(nil, server.name, RPL_MOTD, client.nick, line)
  494. }
  495. rb.Add(nil, server.name, RPL_ENDOFMOTD, client.nick, client.t("End of MOTD command"))
  496. }
  497. // wordWrap wraps the given text into a series of lines that don't exceed lineWidth characters.
  498. func wordWrap(text string, lineWidth int) []string {
  499. var lines []string
  500. var cacheLine, cacheWord string
  501. for _, char := range text {
  502. if char == '\r' {
  503. continue
  504. } else if char == '\n' {
  505. cacheLine += cacheWord
  506. lines = append(lines, cacheLine)
  507. cacheWord = ""
  508. cacheLine = ""
  509. } else if (char == ' ' || char == '-') && len(cacheLine)+len(cacheWord)+1 < lineWidth {
  510. // natural word boundary
  511. cacheLine += cacheWord + string(char)
  512. cacheWord = ""
  513. } else if lineWidth <= len(cacheLine)+len(cacheWord)+1 {
  514. // time to wrap to next line
  515. if len(cacheLine) < (lineWidth / 2) {
  516. // this word takes up more than half a line... just split in the middle of the word
  517. cacheLine += cacheWord + string(char)
  518. cacheWord = ""
  519. } else {
  520. cacheWord += string(char)
  521. }
  522. lines = append(lines, cacheLine)
  523. cacheLine = ""
  524. } else {
  525. // normal character
  526. cacheWord += string(char)
  527. }
  528. }
  529. if 0 < len(cacheWord) {
  530. cacheLine += cacheWord
  531. }
  532. if 0 < len(cacheLine) {
  533. lines = append(lines, cacheLine)
  534. }
  535. return lines
  536. }
  537. // SplitMessage represents a message that's been split for sending.
  538. type SplitMessage struct {
  539. For512 []string
  540. ForMaxLine string
  541. }
  542. func (server *Server) splitMessage(original string, origIs512 bool) SplitMessage {
  543. var newSplit SplitMessage
  544. newSplit.ForMaxLine = original
  545. if !origIs512 {
  546. newSplit.For512 = wordWrap(original, 400)
  547. } else {
  548. newSplit.For512 = []string{original}
  549. }
  550. return newSplit
  551. }
  552. // WhoisChannelsNames returns the common channel names between two users.
  553. func (client *Client) WhoisChannelsNames(target *Client) []string {
  554. isMultiPrefix := client.capabilities.Has(caps.MultiPrefix)
  555. var chstrs []string
  556. for _, channel := range target.Channels() {
  557. // channel is secret and the target can't see it
  558. if !client.HasMode(modes.Operator) {
  559. if (target.HasMode(modes.Invisible) || channel.flags.HasMode(modes.Secret)) && !channel.hasClient(client) {
  560. continue
  561. }
  562. }
  563. chstrs = append(chstrs, channel.ClientPrefixes(target, isMultiPrefix)+channel.name)
  564. }
  565. return chstrs
  566. }
  567. func (client *Client) getWhoisOf(target *Client, rb *ResponseBuffer) {
  568. target.stateMutex.RLock()
  569. defer target.stateMutex.RUnlock()
  570. rb.Add(nil, client.server.name, RPL_WHOISUSER, client.nick, target.nick, target.username, target.hostname, "*", target.realname)
  571. whoischannels := client.WhoisChannelsNames(target)
  572. if whoischannels != nil {
  573. rb.Add(nil, client.server.name, RPL_WHOISCHANNELS, client.nick, target.nick, strings.Join(whoischannels, " "))
  574. }
  575. tOper := target.Oper()
  576. if tOper != nil {
  577. rb.Add(nil, client.server.name, RPL_WHOISOPERATOR, client.nick, target.nick, tOper.WhoisLine)
  578. }
  579. if client.HasMode(modes.Operator) || client == target {
  580. rb.Add(nil, client.server.name, RPL_WHOISACTUALLY, client.nick, target.nick, fmt.Sprintf("%s@%s", target.username, utils.LookupHostname(target.IPString())), target.IPString(), client.t("Actual user@host, Actual IP"))
  581. }
  582. if target.HasMode(modes.TLS) {
  583. rb.Add(nil, client.server.name, RPL_WHOISSECURE, client.nick, target.nick, client.t("is using a secure connection"))
  584. }
  585. if target.LoggedIntoAccount() {
  586. rb.Add(nil, client.server.name, RPL_WHOISACCOUNT, client.nick, target.AccountName(), client.t("is logged in as"))
  587. }
  588. if target.HasMode(modes.Bot) {
  589. rb.Add(nil, client.server.name, RPL_WHOISBOT, client.nick, target.nick, ircfmt.Unescape(fmt.Sprintf(client.t("is a $bBot$b on %s"), client.server.networkName)))
  590. }
  591. if 0 < len(target.languages) {
  592. params := []string{client.nick, target.nick}
  593. for _, str := range client.server.languages.Codes(target.languages) {
  594. params = append(params, str)
  595. }
  596. params = append(params, client.t("can speak these languages"))
  597. rb.Add(nil, client.server.name, RPL_WHOISLANGUAGE, params...)
  598. }
  599. if target.certfp != "" && (client.HasMode(modes.Operator) || client == target) {
  600. rb.Add(nil, client.server.name, RPL_WHOISCERTFP, client.nick, target.nick, fmt.Sprintf(client.t("has client certificate fingerprint %s"), target.certfp))
  601. }
  602. rb.Add(nil, client.server.name, RPL_WHOISIDLE, client.nick, target.nick, strconv.FormatUint(target.IdleSeconds(), 10), strconv.FormatInt(target.SignonTime(), 10), client.t("seconds idle, signon time"))
  603. }
  604. // rplWhoReply returns the WHO reply between one user and another channel/user.
  605. // <channel> <user> <host> <server> <nick> ( "H" / "G" ) ["*"] [ ( "@" / "+" ) ]
  606. // :<hopcount> <real name>
  607. func (target *Client) rplWhoReply(channel *Channel, client *Client, rb *ResponseBuffer) {
  608. channelName := "*"
  609. flags := ""
  610. if client.HasMode(modes.Away) {
  611. flags = "G"
  612. } else {
  613. flags = "H"
  614. }
  615. if client.HasMode(modes.Operator) {
  616. flags += "*"
  617. }
  618. if channel != nil {
  619. flags += channel.ClientPrefixes(client, target.capabilities.Has(caps.MultiPrefix))
  620. channelName = channel.name
  621. }
  622. 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())
  623. }
  624. func whoChannel(client *Client, channel *Channel, friends ClientSet, rb *ResponseBuffer) {
  625. for _, member := range channel.Members() {
  626. if !client.HasMode(modes.Invisible) || friends[client] {
  627. client.rplWhoReply(channel, member, rb)
  628. }
  629. }
  630. }
  631. // rehash reloads the config and applies the changes from the config file.
  632. func (server *Server) rehash() error {
  633. server.logger.Debug("rehash", "Starting rehash")
  634. // only let one REHASH go on at a time
  635. server.rehashMutex.Lock()
  636. defer server.rehashMutex.Unlock()
  637. server.logger.Debug("rehash", "Got rehash lock")
  638. config, err := LoadConfig(server.configFilename)
  639. if err != nil {
  640. return fmt.Errorf("Error loading config file config: %s", err.Error())
  641. }
  642. err = server.applyConfig(config, false)
  643. if err != nil {
  644. return fmt.Errorf("Error applying config changes: %s", err.Error())
  645. }
  646. return nil
  647. }
  648. func (server *Server) applyConfig(config *Config, initial bool) error {
  649. if initial {
  650. server.ctime = time.Now()
  651. server.configFilename = config.Filename
  652. } else {
  653. // enforce configs that can't be changed after launch:
  654. if server.limits.LineLen.Tags != config.Limits.LineLen.Tags || server.limits.LineLen.Rest != config.Limits.LineLen.Rest {
  655. return fmt.Errorf("Maximum line length (linelen) cannot be changed after launching the server, rehash aborted")
  656. } else if server.name != config.Server.Name {
  657. return fmt.Errorf("Server name cannot be changed after launching the server, rehash aborted")
  658. } else if server.config.Datastore.Path != config.Datastore.Path {
  659. return fmt.Errorf("Datastore path cannot be changed after launching the server, rehash aborted")
  660. }
  661. }
  662. server.logger.Info("rehash", "Using config file", server.configFilename)
  663. casefoldedName, err := Casefold(config.Server.Name)
  664. if err != nil {
  665. return fmt.Errorf("Server name isn't valid [%s]: %s", config.Server.Name, err.Error())
  666. }
  667. // confirm operator stuff all exists and is fine
  668. operclasses, err := config.OperatorClasses()
  669. if err != nil {
  670. return fmt.Errorf("Error rehashing config file operclasses: %s", err.Error())
  671. }
  672. opers, err := config.Operators(operclasses)
  673. if err != nil {
  674. return fmt.Errorf("Error rehashing config file opers: %s", err.Error())
  675. }
  676. // TODO: support rehash of existing operator perms?
  677. // sanity checks complete, start modifying server state
  678. if initial {
  679. server.name = config.Server.Name
  680. server.nameCasefolded = casefoldedName
  681. }
  682. server.configurableStateMutex.Lock()
  683. server.networkName = config.Network.Name
  684. if config.Server.Password != "" {
  685. server.password = config.Server.PasswordBytes()
  686. } else {
  687. server.password = nil
  688. }
  689. // apply new WebIRC command restrictions
  690. server.webirc = config.Server.WebIRC
  691. // apply new PROXY command restrictions
  692. server.proxyAllowedFrom = config.Server.ProxyAllowedFrom
  693. server.recoverFromErrors = true
  694. if config.Debug.RecoverFromErrors != nil {
  695. server.recoverFromErrors = *config.Debug.RecoverFromErrors
  696. }
  697. server.configurableStateMutex.Unlock()
  698. err = server.connectionLimiter.ApplyConfig(config.Server.ConnectionLimiter)
  699. if err != nil {
  700. return err
  701. }
  702. err = server.connectionThrottler.ApplyConfig(config.Server.ConnectionThrottler)
  703. if err != nil {
  704. return err
  705. }
  706. // setup new and removed caps
  707. addedCaps := caps.NewSet()
  708. removedCaps := caps.NewSet()
  709. updatedCaps := caps.NewSet()
  710. // Translations
  711. currentLanguageValue, _ := CapValues.Get(caps.Languages)
  712. langCodes := []string{strconv.Itoa(len(config.Languages.Data) + 1), "en"}
  713. for _, info := range config.Languages.Data {
  714. if info.Incomplete {
  715. langCodes = append(langCodes, "~"+info.Code)
  716. } else {
  717. langCodes = append(langCodes, info.Code)
  718. }
  719. }
  720. newLanguageValue := strings.Join(langCodes, ",")
  721. server.logger.Debug("rehash", "Languages:", newLanguageValue)
  722. if currentLanguageValue != newLanguageValue {
  723. updatedCaps.Add(caps.Languages)
  724. CapValues.Set(caps.Languages, newLanguageValue)
  725. }
  726. lm := languages.NewManager(config.Languages.Default, config.Languages.Data)
  727. server.logger.Debug("rehash", "Regenerating HELP indexes for new languages")
  728. GenerateHelpIndices(lm)
  729. server.languages = lm
  730. // SASL
  731. oldAccountConfig := server.AccountConfig()
  732. authPreviouslyEnabled := oldAccountConfig != nil && oldAccountConfig.AuthenticationEnabled
  733. if config.Accounts.AuthenticationEnabled && !authPreviouslyEnabled {
  734. // enabling SASL
  735. SupportedCapabilities.Enable(caps.SASL)
  736. CapValues.Set(caps.SASL, "PLAIN,EXTERNAL")
  737. addedCaps.Add(caps.SASL)
  738. } else if !config.Accounts.AuthenticationEnabled && authPreviouslyEnabled {
  739. // disabling SASL
  740. SupportedCapabilities.Disable(caps.SASL)
  741. removedCaps.Add(caps.SASL)
  742. }
  743. nickReservationPreviouslyDisabled := oldAccountConfig != nil && !oldAccountConfig.NickReservation.Enabled
  744. nickReservationNowEnabled := config.Accounts.NickReservation.Enabled
  745. if nickReservationPreviouslyDisabled && nickReservationNowEnabled {
  746. server.accounts.buildNickToAccountIndex()
  747. }
  748. hsPreviouslyDisabled := oldAccountConfig != nil && !oldAccountConfig.VHosts.Enabled
  749. hsNowEnabled := config.Accounts.VHosts.Enabled
  750. if hsPreviouslyDisabled && hsNowEnabled {
  751. server.accounts.initVHostRequestQueue()
  752. }
  753. // STS
  754. stsValue := config.Server.STS.Value()
  755. var stsDisabled bool
  756. stsCurrentCapValue, _ := CapValues.Get(caps.STS)
  757. server.logger.Debug("rehash", "STS Vals", stsCurrentCapValue, stsValue, fmt.Sprintf("server[%v] config[%v]", server.stsEnabled, config.Server.STS.Enabled))
  758. if config.Server.STS.Enabled && !server.stsEnabled {
  759. // enabling STS
  760. SupportedCapabilities.Enable(caps.STS)
  761. addedCaps.Add(caps.STS)
  762. CapValues.Set(caps.STS, stsValue)
  763. } else if !config.Server.STS.Enabled && server.stsEnabled {
  764. // disabling STS
  765. SupportedCapabilities.Disable(caps.STS)
  766. removedCaps.Add(caps.STS)
  767. stsDisabled = true
  768. } else if config.Server.STS.Enabled && server.stsEnabled && stsValue != stsCurrentCapValue {
  769. // STS policy updated
  770. CapValues.Set(caps.STS, stsValue)
  771. updatedCaps.Add(caps.STS)
  772. }
  773. server.stsEnabled = config.Server.STS.Enabled
  774. // burst new and removed caps
  775. var capBurstClients ClientSet
  776. added := make(map[caps.Version]string)
  777. var removed string
  778. // updated caps get DEL'd and then NEW'd
  779. // so, we can just add updated ones to both removed and added lists here and they'll be correctly handled
  780. server.logger.Debug("rehash", "Updated Caps", updatedCaps.String(caps.Cap301, CapValues))
  781. addedCaps.Union(updatedCaps)
  782. removedCaps.Union(updatedCaps)
  783. if !addedCaps.Empty() || !removedCaps.Empty() {
  784. capBurstClients = server.clients.AllWithCaps(caps.CapNotify)
  785. added[caps.Cap301] = addedCaps.String(caps.Cap301, CapValues)
  786. added[caps.Cap302] = addedCaps.String(caps.Cap302, CapValues)
  787. // removed never has values, so we leave it as Cap301
  788. removed = removedCaps.String(caps.Cap301, CapValues)
  789. }
  790. for sClient := range capBurstClients {
  791. if stsDisabled {
  792. // remove STS policy
  793. //TODO(dan): this is an ugly hack. we can write this better.
  794. stsPolicy := "sts=duration=0"
  795. if !addedCaps.Empty() {
  796. added[caps.Cap302] = added[caps.Cap302] + " " + stsPolicy
  797. } else {
  798. addedCaps.Enable(caps.STS)
  799. added[caps.Cap302] = stsPolicy
  800. }
  801. }
  802. // DEL caps and then send NEW ones so that updated caps get removed/added correctly
  803. if !removedCaps.Empty() {
  804. sClient.Send(nil, server.name, "CAP", sClient.nick, "DEL", removed)
  805. }
  806. if !addedCaps.Empty() {
  807. sClient.Send(nil, server.name, "CAP", sClient.nick, "NEW", added[sClient.capVersion])
  808. }
  809. }
  810. // set server options
  811. server.configurableStateMutex.Lock()
  812. lineLenConfig := LineLenLimits{
  813. Tags: config.Limits.LineLen.Tags,
  814. Rest: config.Limits.LineLen.Rest,
  815. }
  816. server.limits = Limits{
  817. AwayLen: int(config.Limits.AwayLen),
  818. ChannelLen: int(config.Limits.ChannelLen),
  819. KickLen: int(config.Limits.KickLen),
  820. MonitorEntries: int(config.Limits.MonitorEntries),
  821. NickLen: int(config.Limits.NickLen),
  822. TopicLen: int(config.Limits.TopicLen),
  823. ChanListModes: int(config.Limits.ChanListModes),
  824. LineLen: lineLenConfig,
  825. }
  826. server.operclasses = operclasses
  827. server.operators = opers
  828. server.checkIdent = config.Server.CheckIdent
  829. server.defaultChannelModes = ParseDefaultChannelModes(config)
  830. server.configurableStateMutex.Unlock()
  831. // set new sendqueue size
  832. server.SetMaxSendQBytes(config.Server.MaxSendQBytes)
  833. server.loadMOTD(config.Server.MOTD, config.Server.MOTDFormatting)
  834. // reload logging config
  835. err = server.logger.ApplyConfig(config.Logging)
  836. if err != nil {
  837. return err
  838. }
  839. nowLoggingRawIO := server.logger.IsLoggingRawIO()
  840. // notify clients if raw i/o logging was enabled by a rehash
  841. sendRawOutputNotice := !initial && !server.loggingRawIO && nowLoggingRawIO
  842. server.loggingRawIO = nowLoggingRawIO
  843. // save a pointer to the new config
  844. server.configurableStateMutex.Lock()
  845. server.config = config
  846. server.configurableStateMutex.Unlock()
  847. server.logger.Info("rehash", "Using datastore", config.Datastore.Path)
  848. if initial {
  849. if err := server.loadDatastore(config); err != nil {
  850. return err
  851. }
  852. }
  853. server.setupPprofListener(config)
  854. // set RPL_ISUPPORT
  855. var newISupportReplies [][]string
  856. oldISupportList := server.ISupport()
  857. server.setISupport()
  858. if oldISupportList != nil {
  859. newISupportReplies = oldISupportList.GetDifference(server.ISupport())
  860. }
  861. // we are now open for business
  862. server.setupListeners(config)
  863. if !initial {
  864. // push new info to all of our clients
  865. for _, sClient := range server.clients.AllClients() {
  866. for _, tokenline := range newISupportReplies {
  867. sClient.Send(nil, server.name, RPL_ISUPPORT, append([]string{sClient.nick}, tokenline...)...)
  868. }
  869. if sendRawOutputNotice {
  870. 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."))
  871. }
  872. }
  873. }
  874. return nil
  875. }
  876. func (server *Server) setupPprofListener(config *Config) {
  877. pprofListener := ""
  878. if config.Debug.PprofListener != nil {
  879. pprofListener = *config.Debug.PprofListener
  880. }
  881. if server.pprofServer != nil {
  882. if pprofListener == "" || (pprofListener != server.pprofServer.Addr) {
  883. server.logger.Info("rehash", "Stopping pprof listener", server.pprofServer.Addr)
  884. server.pprofServer.Close()
  885. server.pprofServer = nil
  886. }
  887. }
  888. if pprofListener != "" && server.pprofServer == nil {
  889. ps := http.Server{
  890. Addr: pprofListener,
  891. }
  892. go func() {
  893. if err := ps.ListenAndServe(); err != nil {
  894. server.logger.Error("rehash", fmt.Sprintf("pprof listener failed: %v", err))
  895. }
  896. }()
  897. server.pprofServer = &ps
  898. server.logger.Info("rehash", "Started pprof listener", server.pprofServer.Addr)
  899. }
  900. }
  901. func (server *Server) loadMOTD(motdPath string, useFormatting bool) error {
  902. server.logger.Info("rehash", "Using MOTD", motdPath)
  903. motdLines := make([]string, 0)
  904. if motdPath != "" {
  905. file, err := os.Open(motdPath)
  906. if err == nil {
  907. defer file.Close()
  908. reader := bufio.NewReader(file)
  909. for {
  910. line, err := reader.ReadString('\n')
  911. if err != nil {
  912. break
  913. }
  914. line = strings.TrimRight(line, "\r\n")
  915. if useFormatting {
  916. line = ircfmt.Unescape(line)
  917. }
  918. // "- " is the required prefix for MOTD, we just add it here to make
  919. // bursting it out to clients easier
  920. line = fmt.Sprintf("- %s", line)
  921. motdLines = append(motdLines, line)
  922. }
  923. } else {
  924. return err
  925. }
  926. }
  927. server.configurableStateMutex.Lock()
  928. server.motdLines = motdLines
  929. server.configurableStateMutex.Unlock()
  930. return nil
  931. }
  932. func (server *Server) loadDatastore(config *Config) error {
  933. // open the datastore and load server state for which it (rather than config)
  934. // is the source of truth
  935. db, err := OpenDatabase(config)
  936. if err == nil {
  937. server.store = db
  938. } else {
  939. return fmt.Errorf("Failed to open datastore: %s", err.Error())
  940. }
  941. // load *lines (from the datastores)
  942. server.logger.Debug("startup", "Loading D/Klines")
  943. server.loadDLines()
  944. server.loadKLines()
  945. // load password manager
  946. server.logger.Debug("startup", "Loading passwords")
  947. err = server.store.View(func(tx *buntdb.Tx) error {
  948. saltString, err := tx.Get(keySalt)
  949. if err != nil {
  950. return fmt.Errorf("Could not retrieve salt string: %s", err.Error())
  951. }
  952. salt, err := base64.StdEncoding.DecodeString(saltString)
  953. if err != nil {
  954. return err
  955. }
  956. pwm := passwd.NewSaltedManager(salt)
  957. server.passwords = &pwm
  958. return nil
  959. })
  960. if err != nil {
  961. return fmt.Errorf("Could not load salt: %s", err.Error())
  962. }
  963. server.channelRegistry = NewChannelRegistry(server)
  964. server.accounts = NewAccountManager(server)
  965. return nil
  966. }
  967. func (server *Server) setupListeners(config *Config) {
  968. logListener := func(addr string, tlsconfig *tls.Config) {
  969. server.logger.Info("listeners",
  970. fmt.Sprintf("now listening on %s, tls=%t.", addr, (tlsconfig != nil)),
  971. )
  972. }
  973. // update or destroy all existing listeners
  974. tlsListeners := config.TLSListeners()
  975. for addr := range server.listeners {
  976. currentListener := server.listeners[addr]
  977. var stillConfigured bool
  978. for _, newaddr := range config.Server.Listen {
  979. if newaddr == addr {
  980. stillConfigured = true
  981. break
  982. }
  983. }
  984. // pass new config information to the listener, to be picked up after
  985. // its next Accept(). this is like sending over a buffered channel of
  986. // size 1, but where sending a second item overwrites the buffered item
  987. // instead of blocking.
  988. currentListener.configMutex.Lock()
  989. currentListener.shouldStop = !stillConfigured
  990. currentListener.tlsConfig = tlsListeners[addr]
  991. currentListener.configMutex.Unlock()
  992. if stillConfigured {
  993. logListener(addr, currentListener.tlsConfig)
  994. } else {
  995. // tell the listener it should stop by interrupting its Accept() call:
  996. currentListener.listener.Close()
  997. delete(server.listeners, addr)
  998. server.logger.Info("listeners", fmt.Sprintf("stopped listening on %s.", addr))
  999. }
  1000. }
  1001. // create new listeners that were not previously configured
  1002. for _, newaddr := range config.Server.Listen {
  1003. _, exists := server.listeners[newaddr]
  1004. if !exists {
  1005. // make new listener
  1006. tlsConfig := tlsListeners[newaddr]
  1007. server.listeners[newaddr] = server.createListener(newaddr, tlsConfig)
  1008. logListener(newaddr, tlsConfig)
  1009. }
  1010. }
  1011. if len(tlsListeners) == 0 {
  1012. server.logger.Warning("startup", "You are not exposing an SSL/TLS listening port. You should expose at least one port (typically 6697) to accept TLS connections")
  1013. }
  1014. var usesStandardTLSPort bool
  1015. for addr := range config.TLSListeners() {
  1016. if strings.Contains(addr, "6697") {
  1017. usesStandardTLSPort = true
  1018. break
  1019. }
  1020. }
  1021. if 0 < len(tlsListeners) && !usesStandardTLSPort {
  1022. server.logger.Warning("startup", "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")
  1023. }
  1024. }
  1025. // elistMatcher takes and matches ELIST conditions
  1026. type elistMatcher struct {
  1027. MinClientsActive bool
  1028. MinClients int
  1029. MaxClientsActive bool
  1030. MaxClients int
  1031. }
  1032. // Matches checks whether the given channel matches our matches.
  1033. func (matcher *elistMatcher) Matches(channel *Channel) bool {
  1034. if matcher.MinClientsActive {
  1035. if len(channel.Members()) < matcher.MinClients {
  1036. return false
  1037. }
  1038. }
  1039. if matcher.MaxClientsActive {
  1040. if len(channel.Members()) < len(channel.members) {
  1041. return false
  1042. }
  1043. }
  1044. return true
  1045. }
  1046. // RplList returns the RPL_LIST numeric for the given channel.
  1047. func (target *Client) RplList(channel *Channel, rb *ResponseBuffer) {
  1048. // get the correct number of channel members
  1049. var memberCount int
  1050. if target.HasMode(modes.Operator) || channel.hasClient(target) {
  1051. memberCount = len(channel.Members())
  1052. } else {
  1053. for _, member := range channel.Members() {
  1054. if !member.HasMode(modes.Invisible) {
  1055. memberCount++
  1056. }
  1057. }
  1058. }
  1059. rb.Add(nil, target.server.name, RPL_LIST, target.nick, channel.name, strconv.Itoa(memberCount), channel.topic)
  1060. }
  1061. // ResumeDetails are the details that we use to resume connections.
  1062. type ResumeDetails struct {
  1063. OldNick string
  1064. Timestamp *time.Time
  1065. SendFakeJoinsFor []string
  1066. }
  1067. var (
  1068. infoString1 = strings.Split(` ▄▄▄ ▄▄▄· ▄▄ • ▐ ▄
  1069. ▪ ▀▄ █·▐█ ▀█ ▐█ ▀ ▪▪ •█▌▐█▪
  1070. ▄█▀▄ ▐▀▀▄ ▄█▀▀█ ▄█ ▀█▄ ▄█▀▄▪▐█▐▐▌ ▄█▀▄
  1071. ▐█▌.▐▌▐█•█▌▐█ ▪▐▌▐█▄▪▐█▐█▌ ▐▌██▐█▌▐█▌.▐▌
  1072. ▀█▄▀▪.▀ ▀ ▀ ▀ ·▀▀▀▀ ▀█▄▀ ▀▀ █▪ ▀█▄▀▪
  1073. https://oragono.io/
  1074. https://github.com/oragono/oragono
  1075. https://crowdin.com/project/oragono
  1076. `, "\n")
  1077. infoString2 = strings.Split(` Daniel Oakley, DanielOaks, <daniel@danieloaks.net>
  1078. Shivaram Lingamneni, slingamn, <slingamn@cs.stanford.edu>
  1079. `, "\n")
  1080. infoString3 = strings.Split(` 3onyc
  1081. Edmund Huber
  1082. Euan Kemp (euank)
  1083. Jeremy Latt
  1084. Martin Lindhe (martinlindhe)
  1085. Roberto Besser (besser)
  1086. Robin Burchell (rburchell)
  1087. Sean Enck (enckse)
  1088. soul9
  1089. Vegax
  1090. `, "\n")
  1091. )