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.

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