Testing ground for GUI
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.

main.go 84KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457
  1. //
  2. // Copyright (c) 2014 - 2018, Přemysl Janouch <p@janouch.name>
  3. //
  4. // Permission to use, copy, modify, and/or distribute this software for any
  5. // purpose with or without fee is hereby granted.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. //
  15. // hid is a straight-forward port of kike IRCd from C.
  16. package main
  17. import (
  18. "bufio"
  19. "bytes"
  20. "crypto/sha256"
  21. "crypto/tls"
  22. "encoding/hex"
  23. "errors"
  24. "flag"
  25. "fmt"
  26. "io"
  27. "io/ioutil"
  28. "log/syslog"
  29. "net"
  30. "os"
  31. "os/signal"
  32. "os/user"
  33. "path/filepath"
  34. "regexp"
  35. "strconv"
  36. "strings"
  37. "syscall"
  38. "time"
  39. )
  40. var debugMode = false
  41. const (
  42. projectName = "hid"
  43. // TODO: Consider using the same version number for all subprojects.
  44. projectVersion = "0"
  45. )
  46. // --- Logging -----------------------------------------------------------------
  47. type logPrio int
  48. const (
  49. prioFatal logPrio = iota
  50. prioError
  51. prioWarning
  52. prioStatus
  53. prioDebug
  54. )
  55. func (lp logPrio) prefix() string {
  56. switch lp {
  57. case prioFatal:
  58. return "fatal: "
  59. case prioError:
  60. return "error: "
  61. case prioWarning:
  62. return "warning: "
  63. case prioStatus:
  64. return ""
  65. case prioDebug:
  66. return "debug: "
  67. default:
  68. panic("unhandled log priority")
  69. }
  70. }
  71. func (lp logPrio) syslogPrio() syslog.Priority {
  72. switch lp {
  73. case prioFatal:
  74. return syslog.LOG_ERR
  75. case prioError:
  76. return syslog.LOG_ERR
  77. case prioWarning:
  78. return syslog.LOG_WARNING
  79. case prioStatus:
  80. return syslog.LOG_INFO
  81. case prioDebug:
  82. return syslog.LOG_DEBUG
  83. default:
  84. panic("unhandled log priority")
  85. }
  86. }
  87. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  88. func logMessageStdio(prio logPrio, format string, args ...interface{}) {
  89. // TODO: isatty-enabled colors based on prio.
  90. os.Stderr.WriteString(time.Now().Format("2006-01-02 15:04:05 ") +
  91. prio.prefix() + fmt.Sprintf(format, args...) + "\n")
  92. }
  93. func logMessageSystemd(prio logPrio, format string, args ...interface{}) {
  94. if prio == prioFatal {
  95. // There is no corresponding syslog severity.
  96. format = "fatal: " + format
  97. }
  98. fmt.Fprintf(os.Stderr, "<%d>%s\n",
  99. prio.syslogPrio(), fmt.Sprintf(format, args...))
  100. }
  101. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  102. var logMessage = logMessageStdio
  103. func printDebug(format string, args ...interface{}) {
  104. if debugMode {
  105. logMessage(prioDebug, format, args...)
  106. }
  107. }
  108. func printStatus(format string, args ...interface{}) {
  109. logMessage(prioStatus, format, args...)
  110. }
  111. func printWarning(format string, args ...interface{}) {
  112. logMessage(prioWarning, format, args...)
  113. }
  114. func printError(format string, args ...interface{}) {
  115. logMessage(prioError, format, args...)
  116. }
  117. // "fatal" is reserved for failures that would harm further operation.
  118. func printFatal(format string, args ...interface{}) {
  119. logMessage(prioFatal, format, args...)
  120. }
  121. func exitFatal(format string, args ...interface{}) {
  122. printFatal(format, args...)
  123. os.Exit(1)
  124. }
  125. // --- Utilities ---------------------------------------------------------------
  126. // Split a string by a set of UTF-8 delimiters, optionally ignoring empty items.
  127. func splitString(s, delims string, ignoreEmpty bool) (result []string) {
  128. for {
  129. end := strings.IndexAny(s, delims)
  130. if end < 0 {
  131. break
  132. }
  133. if !ignoreEmpty || end != 0 {
  134. result = append(result, s[:end])
  135. }
  136. s = s[end+1:]
  137. }
  138. if !ignoreEmpty || s != "" {
  139. result = append(result, s)
  140. }
  141. return
  142. }
  143. //
  144. // Trivial SSL/TLS autodetection. The first block of data returned by Recvfrom
  145. // must be at least three octets long for this to work reliably, but that should
  146. // not pose a problem in practice. We might try waiting for them.
  147. //
  148. // SSL2: 1xxx xxxx | xxxx xxxx | <1>
  149. // (message length) (client hello)
  150. // SSL3/TLS: <22> | <3> | xxxx xxxx
  151. // (handshake)| (protocol version)
  152. //
  153. func detectTLS(sysconn syscall.RawConn) (isTLS bool) {
  154. sysconn.Read(func(fd uintptr) (done bool) {
  155. var buf [3]byte
  156. n, _, err := syscall.Recvfrom(int(fd), buf[:], syscall.MSG_PEEK)
  157. switch {
  158. case n == 3:
  159. isTLS = buf[0]&0x80 != 0 && buf[2] == 1
  160. fallthrough
  161. case n == 2:
  162. isTLS = isTLS || buf[0] == 22 && buf[1] == 3
  163. case n == 1:
  164. isTLS = buf[0] == 22
  165. case err == syscall.EAGAIN:
  166. return false
  167. }
  168. return true
  169. })
  170. return isTLS
  171. }
  172. // --- File system -------------------------------------------------------------
  173. // Look up the value of an XDG path from environment, or fall back to a default.
  174. func getXDGHomeDir(name, def string) string {
  175. env := os.Getenv(name)
  176. if env != "" && env[0] == filepath.Separator {
  177. return env
  178. }
  179. home := ""
  180. if v, ok := os.LookupEnv("HOME"); ok {
  181. home = v
  182. } else if u, _ := user.Current(); u != nil {
  183. home = u.HomeDir
  184. }
  185. return filepath.Join(home, def)
  186. }
  187. func resolveRelativeFilenameGeneric(paths []string, filename string) string {
  188. for _, path := range paths {
  189. // As per XDG spec, relative paths are ignored.
  190. if path == "" || path[0] != filepath.Separator {
  191. continue
  192. }
  193. file := filepath.Join(path, filename)
  194. if _, err := os.Stat(file); err == nil {
  195. return file
  196. }
  197. }
  198. return ""
  199. }
  200. // Retrieve all XDG base directories for configuration files.
  201. func getXDGConfigDirs() (result []string) {
  202. home := getXDGHomeDir("XDG_CONFIG_HOME", ".config")
  203. if home != "" {
  204. result = append(result, home)
  205. }
  206. dirs := os.Getenv("XDG_CONFIG_DIRS")
  207. if dirs == "" {
  208. dirs = "/etc/xdg"
  209. }
  210. for _, path := range strings.Split(dirs, ":") {
  211. if path != "" {
  212. result = append(result, path)
  213. }
  214. }
  215. return
  216. }
  217. func resolveRelativeConfigFilename(filename string) string {
  218. return resolveRelativeFilenameGeneric(getXDGConfigDirs(),
  219. filepath.Join(projectName, filename))
  220. }
  221. func findTildeHome(username string) string {
  222. if username != "" {
  223. if u, _ := user.Lookup(username); u != nil {
  224. return u.HomeDir
  225. }
  226. } else if u, _ := user.Current(); u != nil {
  227. return u.HomeDir
  228. } else if v, ok := os.LookupEnv("HOME"); ok {
  229. return v
  230. }
  231. printDebug("failed to expand the home directory for %s", username)
  232. return "~" + username
  233. }
  234. func resolveFilename(filename string, relativeCB func(string) string) string {
  235. // Absolute path is absolute.
  236. if filename == "" || filename[0] == filepath.Separator {
  237. return filename
  238. }
  239. if filename[0] != '~' {
  240. return relativeCB(filename)
  241. }
  242. // Paths to home directories ought to be absolute.
  243. var n int
  244. for n = 0; n < len(filename); n++ {
  245. if filename[n] == filepath.Separator {
  246. break
  247. }
  248. }
  249. return findTildeHome(filename[1:n]) + filename[n:]
  250. }
  251. // --- Simple file I/O ---------------------------------------------------------
  252. // Overwrites filename contents with data; creates directories as needed.
  253. func writeFile(path string, data []byte) error {
  254. if dir := filepath.Dir(path); dir != "." {
  255. if err := os.MkdirAll(dir, 0755); err != nil {
  256. return err
  257. }
  258. }
  259. return ioutil.WriteFile(path, data, 0644)
  260. }
  261. // Wrapper for writeFile that makes sure that the new data has been written
  262. // to disk in its entirety before overriding the old file.
  263. func writeFileSafe(path string, data []byte) error {
  264. temp := path + ".new"
  265. if err := writeFile(temp, data); err != nil {
  266. return err
  267. }
  268. return os.Rename(temp, path)
  269. }
  270. // --- Simple configuration ----------------------------------------------------
  271. // This is the bare minimum to make an application configurable.
  272. // Keys are stripped of surrounding whitespace, values are not.
  273. type simpleConfigItem struct {
  274. key string // INI key
  275. def string // default value
  276. description string // documentation
  277. }
  278. type simpleConfig map[string]string
  279. func (sc simpleConfig) loadDefaults(table []simpleConfigItem) {
  280. for _, item := range table {
  281. sc[item.key] = item.def
  282. }
  283. }
  284. func (sc simpleConfig) updateFromFile() error {
  285. basename := projectName + ".conf"
  286. path := resolveFilename(basename, resolveRelativeConfigFilename)
  287. if path == "" {
  288. return &os.PathError{
  289. Op: "cannot find",
  290. Path: basename,
  291. Err: os.ErrNotExist,
  292. }
  293. }
  294. f, err := os.Open(path)
  295. if err != nil {
  296. return err
  297. }
  298. defer f.Close()
  299. scanner := bufio.NewScanner(f)
  300. for lineNo := 1; scanner.Scan(); lineNo++ {
  301. line := strings.TrimLeft(scanner.Text(), " \t")
  302. if line == "" || strings.HasPrefix(line, "#") {
  303. continue
  304. }
  305. equals := strings.IndexByte(line, '=')
  306. if equals <= 0 {
  307. return fmt.Errorf("%s:%d: malformed line", path, lineNo)
  308. }
  309. sc[strings.TrimRight(line[:equals], " \t")] = line[equals+1:]
  310. }
  311. return scanner.Err()
  312. }
  313. func writeConfigurationFile(pathHint string, data []byte) (string, error) {
  314. path := pathHint
  315. if path == "" {
  316. path = filepath.Join(getXDGHomeDir("XDG_CONFIG_HOME", ".config"),
  317. projectName, projectName+".conf")
  318. }
  319. if err := writeFileSafe(path, data); err != nil {
  320. return "", err
  321. }
  322. return path, nil
  323. }
  324. func simpleConfigWriteDefault(pathHint string, prolog string,
  325. table []simpleConfigItem) (string, error) {
  326. data := []byte(prolog)
  327. for _, item := range table {
  328. data = append(data, fmt.Sprintf("# %s\n%s=%s\n",
  329. item.description, item.key, item.def)...)
  330. }
  331. return writeConfigurationFile(pathHint, data)
  332. }
  333. /// Convenience wrapper suitable for most simple applications.
  334. func callSimpleConfigWriteDefault(pathHint string, table []simpleConfigItem) {
  335. prologLines := []string{
  336. `# ` + projectName + ` ` + projectVersion + ` configuration file`,
  337. "#",
  338. `# Relative paths are searched for in ${XDG_CONFIG_HOME:-~/.config}`,
  339. `# /` + projectName + ` as well as in $XDG_CONFIG_DIRS/` + projectName,
  340. ``,
  341. ``,
  342. }
  343. path, err := simpleConfigWriteDefault(
  344. pathHint, strings.Join(prologLines, "\n"), table)
  345. if err != nil {
  346. exitFatal("%s", err)
  347. }
  348. printStatus("configuration written to `%s'", path)
  349. }
  350. // --- Configuration -----------------------------------------------------------
  351. var configTable = []simpleConfigItem{
  352. {"server_name", "", "Server name"},
  353. {"server_info", "My server", "Brief server description"},
  354. {"motd", "", "MOTD filename"},
  355. {"catalog", "", "Localisation catalog"},
  356. {"bind", ":6667", "Bind addresses of the IRC server"},
  357. {"tls_cert", "", "Server TLS certificate (PEM)"},
  358. {"tls_key", "", "Server TLS private key (PEM)"},
  359. {"operators", "", "IRCop TLS certificate SHA-256 fingerprints"},
  360. {"max_connections", "0", "Global connection limit"},
  361. {"ping_interval", "180", "Interval between PINGs (sec)"},
  362. }
  363. // --- Rate limiter ------------------------------------------------------------
  364. type floodDetector struct {
  365. interval time.Duration // interval for the limit in seconds
  366. limit uint // maximum number of events allowed
  367. timestamps []time.Time // timestamps of last events
  368. pos uint // index of the oldest event
  369. }
  370. func newFloodDetector(interval time.Duration, limit uint) *floodDetector {
  371. return &floodDetector{
  372. interval: interval,
  373. limit: limit,
  374. timestamps: make([]time.Time, limit+1),
  375. pos: 0,
  376. }
  377. }
  378. func (fd *floodDetector) check() bool {
  379. now := time.Now()
  380. fd.timestamps[fd.pos] = now
  381. fd.pos++
  382. if fd.pos > fd.limit {
  383. fd.pos = 0
  384. }
  385. var count uint
  386. begin := now.Add(-fd.interval)
  387. for _, ts := range fd.timestamps {
  388. if ts.After(begin) {
  389. count++
  390. }
  391. }
  392. return count <= fd.limit
  393. }
  394. // --- IRC protocol ------------------------------------------------------------
  395. //go:generate sh -c "./hid-gen-replies.sh > hid-replies.go < hid-replies"
  396. func ircToLower(c byte) byte {
  397. switch c {
  398. case '[':
  399. return '{'
  400. case ']':
  401. return '}'
  402. case '\\':
  403. return '|'
  404. case '~':
  405. return '^'
  406. }
  407. if c >= 'A' && c <= 'Z' {
  408. return c + ('a' - 'A')
  409. }
  410. return c
  411. }
  412. func ircToUpper(c byte) byte {
  413. switch c {
  414. case '{':
  415. return '['
  416. case '}':
  417. return ']'
  418. case '|':
  419. return '\\'
  420. case '^':
  421. return '~'
  422. }
  423. if c >= 'a' && c <= 'z' {
  424. return c - ('a' - 'A')
  425. }
  426. return c
  427. }
  428. // Convert identifier to a canonical form for case-insensitive comparisons.
  429. // ircToUpper is used so that statically initialized maps can be in uppercase.
  430. func ircToCanon(ident string) string {
  431. var canon []byte
  432. for _, c := range []byte(ident) {
  433. canon = append(canon, ircToUpper(c))
  434. }
  435. return string(canon)
  436. }
  437. func ircEqual(s1, s2 string) bool {
  438. return ircToCanon(s1) == ircToCanon(s2)
  439. }
  440. func ircFnmatch(pattern string, s string) bool {
  441. pattern, s = ircToCanon(pattern), ircToCanon(s)
  442. // FIXME: This should not support [] ranges and handle '/' specially.
  443. // We could translate the pattern to a regular expression.
  444. matched, _ := filepath.Match(pattern, s)
  445. return matched
  446. }
  447. var reMsg = regexp.MustCompile(
  448. `^(?:@([^ ]*) +)?(?::([^! ]*)(?:!([^@]*)@([^ ]*))? +)?([^ ]+)(.*)?$`)
  449. var reArgs = regexp.MustCompile(`:.*| [^: ][^ ]*`)
  450. type message struct {
  451. tags map[string]string // IRC 3.2 message tags
  452. nick string // optional nickname
  453. user string // optional username
  454. host string // optional hostname or IP address
  455. command string // command name
  456. params []string // arguments
  457. }
  458. func ircUnescapeMessageTag(value string) string {
  459. var buf []byte
  460. escape := false
  461. for i := 0; i < len(value); i++ {
  462. if escape {
  463. switch value[i] {
  464. case ':':
  465. buf = append(buf, ';')
  466. case 's':
  467. buf = append(buf, ' ')
  468. case 'r':
  469. buf = append(buf, '\r')
  470. case 'n':
  471. buf = append(buf, '\n')
  472. default:
  473. buf = append(buf, value[i])
  474. }
  475. escape = false
  476. } else if value[i] == '\\' {
  477. escape = true
  478. } else {
  479. buf = append(buf, value[i])
  480. }
  481. }
  482. return string(buf)
  483. }
  484. func ircParseMessageTags(tags string, out map[string]string) {
  485. for _, tag := range splitString(tags, ";", true /* ignoreEmpty */) {
  486. if equal := strings.IndexByte(tag, '='); equal < 0 {
  487. out[tag] = ""
  488. } else {
  489. out[tag[:equal]] = ircUnescapeMessageTag(tag[equal+1:])
  490. }
  491. }
  492. }
  493. func ircParseMessage(line string) *message {
  494. m := reMsg.FindStringSubmatch(line)
  495. if m == nil {
  496. return nil
  497. }
  498. msg := message{nil, m[2], m[3], m[4], m[5], nil}
  499. if m[1] != "" {
  500. msg.tags = make(map[string]string)
  501. ircParseMessageTags(m[1], msg.tags)
  502. }
  503. for _, x := range reArgs.FindAllString(m[6], -1) {
  504. msg.params = append(msg.params, x[1:])
  505. }
  506. return &msg
  507. }
  508. // --- IRC token validation ----------------------------------------------------
  509. // Everything as per RFC 2812
  510. const (
  511. ircMaxNickname = 9
  512. ircMaxHostname = 63
  513. ircMaxChannelName = 50
  514. ircMaxMessageLength = 510
  515. )
  516. const (
  517. reClassSpecial = "\\[\\]\\\\`_^{|}"
  518. // "shortname" from RFC 2812 doesn't work how its author thought it would.
  519. reShortname = "[0-9A-Za-z](-*[0-9A-Za-z])*"
  520. )
  521. var (
  522. reHostname = regexp.MustCompile(
  523. `^` + reShortname + `(\.` + reShortname + `)*$`)
  524. // Extending ASCII to the whole range of Unicode letters.
  525. reNickname = regexp.MustCompile(
  526. `^[\pL` + reClassSpecial + `][\pL` + reClassSpecial + `0-9-]*$`)
  527. // Notably, this won't match invalid UTF-8 characters, although the
  528. // behaviour seems to be unstated in the documentation.
  529. reUsername = regexp.MustCompile(`^[^\0\r\n @]+$`)
  530. reChannelName = regexp.MustCompile(`^[^\0\007\r\n ,:]+$`)
  531. reKey = regexp.MustCompile(`^[^\r\n\f\t\v ]{1,23}$`)
  532. reUserMask = regexp.MustCompile(`^[^!@]+![^!@]+@[^@!]+$`)
  533. reFingerprint = regexp.MustCompile(`^[a-fA-F0-9]{64}$`)
  534. )
  535. func ircValidateHostname(hostname string) error {
  536. if hostname == "" {
  537. return errors.New("the value is empty")
  538. }
  539. if !reHostname.MatchString(hostname) {
  540. return errors.New("invalid format")
  541. }
  542. if len(hostname) > ircMaxHostname {
  543. return errors.New("the value is too long")
  544. }
  545. return nil
  546. }
  547. func ircIsValidNickname(nickname string) bool {
  548. return len(nickname) <= ircMaxNickname && reNickname.MatchString(nickname)
  549. }
  550. func ircIsValidUsername(username string) bool {
  551. // XXX: We really should put a limit on this
  552. // despite the RFC not mentioning one.
  553. return reUsername.MatchString(username)
  554. }
  555. func ircIsValidChannelName(name string) bool {
  556. return len(name) <= ircMaxChannelName && reChannelName.MatchString(name)
  557. }
  558. func ircIsValidKey(key string) bool {
  559. // XXX: Should be 7-bit as well but whatever.
  560. return reKey.MatchString(key)
  561. }
  562. func ircIsValidUserMask(mask string) bool {
  563. return reUserMask.MatchString(mask)
  564. }
  565. func ircIsValidFingerprint(fp string) bool {
  566. return reFingerprint.MatchString(fp)
  567. }
  568. // --- Clients (equals users) --------------------------------------------------
  569. type connCloseWriter interface {
  570. net.Conn
  571. CloseWrite() error
  572. }
  573. const ircSupportedUserModes = "aiwros"
  574. const (
  575. ircUserModeInvisible uint = 1 << iota
  576. ircUserModeRxWallops
  577. ircUserModeRestricted
  578. ircUserModeOperator
  579. ircUserModeRxServerNotices
  580. )
  581. const (
  582. ircCapMultiPrefix uint = 1 << iota
  583. ircCapInviteNotify
  584. ircCapEchoMessage
  585. ircCapUserhostInNames
  586. ircCapServerTime
  587. )
  588. type client struct {
  589. transport net.Conn // underlying connection
  590. tls *tls.Conn // TLS, if detected
  591. conn connCloseWriter // high-level connection
  592. recvQ []byte // unprocessed input
  593. sendQ []byte // unprocessed output
  594. reading bool // whether a reading goroutine is running
  595. writing bool // whether a writing goroutine is running
  596. closing bool // whether we're closing the connection
  597. killTimer *time.Timer // hard kill timeout
  598. opened time.Time // when the connection was opened
  599. nSentMessages uint // number of sent messages total
  600. sentBytes int // number of sent bytes total
  601. nReceivedMessages uint // number of received messages total
  602. receivedBytes int // number of received bytes total
  603. hostname string // hostname or IP shown to the network
  604. port string // port of the peer as a string
  605. address string // full network address
  606. pingTimer *time.Timer // we should send a PING
  607. timeoutTimer *time.Timer // connection seems to be dead
  608. registered bool // the user has registered
  609. capNegotiating bool // negotiating capabilities
  610. capsEnabled uint // enabled capabilities
  611. capVersion uint // CAP protocol version
  612. tlsCertFingerprint string // client certificate fingerprint
  613. nickname string // IRC nickname (main identifier)
  614. username string // IRC username
  615. realname string // IRC realname (or e-mail)
  616. mode uint // user's mode
  617. awayMessage string // away message
  618. lastActive time.Time // last PRIVMSG, to get idle time
  619. invites map[string]bool // channel invitations by operators
  620. antiflood *floodDetector // flood detector
  621. }
  622. // --- Channels ----------------------------------------------------------------
  623. const ircSupportedChanModes = "ov" + "beI" + "imnqpst" + "kl"
  624. const (
  625. ircChanModeInviteOnly uint = 1 << iota
  626. ircChanModeModerated
  627. ircChanModeNoOutsideMsgs
  628. ircChanModeQuiet
  629. ircChanModePrivate
  630. ircChanModeSecret
  631. ircChanModeProtectedTopic
  632. ircChanModeOperator
  633. ircChanModeVoice
  634. )
  635. type channel struct {
  636. name string // channel name
  637. modes uint // channel modes
  638. key string // channel key
  639. userLimit int // user limit or -1
  640. created time.Time // creation time
  641. topic string // channel topic
  642. topicWho string // who set the topic
  643. topicTime time.Time // when the topic was set
  644. userModes map[*client]uint // modes for all channel users
  645. banList []string // ban list
  646. exceptionList []string // exceptions from bans
  647. inviteList []string // exceptions from +I
  648. }
  649. func (ch *channel) getMode(discloseSecrets bool) string {
  650. var buf []byte
  651. if 0 != ch.modes&ircChanModeInviteOnly {
  652. buf = append(buf, 'i')
  653. }
  654. if 0 != ch.modes&ircChanModeModerated {
  655. buf = append(buf, 'm')
  656. }
  657. if 0 != ch.modes&ircChanModeNoOutsideMsgs {
  658. buf = append(buf, 'n')
  659. }
  660. if 0 != ch.modes&ircChanModeQuiet {
  661. buf = append(buf, 'q')
  662. }
  663. if 0 != ch.modes&ircChanModePrivate {
  664. buf = append(buf, 'p')
  665. }
  666. if 0 != ch.modes&ircChanModeSecret {
  667. buf = append(buf, 's')
  668. }
  669. if 0 != ch.modes&ircChanModeProtectedTopic {
  670. buf = append(buf, 'r')
  671. }
  672. if ch.userLimit != -1 {
  673. buf = append(buf, 'l')
  674. }
  675. if ch.key != "" {
  676. buf = append(buf, 'k')
  677. }
  678. // XXX: Is it correct to split it? Try it on an existing implementation.
  679. if discloseSecrets {
  680. if ch.userLimit != -1 {
  681. buf = append(buf, fmt.Sprintf(" %d", ch.userLimit)...)
  682. }
  683. if ch.key != "" {
  684. buf = append(buf, fmt.Sprintf(" %s", ch.key)...)
  685. }
  686. }
  687. return string(buf)
  688. }
  689. // --- IRC server context ------------------------------------------------------
  690. type whowasInfo struct {
  691. nickname, username, realname, hostname string
  692. }
  693. func newWhowasInfo(c *client) *whowasInfo {
  694. return &whowasInfo{
  695. nickname: c.nickname,
  696. username: c.username,
  697. realname: c.realname,
  698. hostname: c.hostname,
  699. }
  700. }
  701. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  702. type ircCommand struct {
  703. requiresRegistration bool
  704. handler func(*message, *client)
  705. nReceived uint // number of commands received
  706. bytesReceived int // number of bytes received total
  707. }
  708. type preparedEvent struct {
  709. client *client
  710. host string // client's hostname or literal IP address
  711. isTLS bool // the client seems to use TLS
  712. }
  713. type readEvent struct {
  714. client *client
  715. data []byte // new data from the client
  716. err error // read error
  717. }
  718. type writeEvent struct {
  719. client *client
  720. written int // amount of bytes written
  721. err error // write error
  722. }
  723. // TODO: Maybe we want to keep it in a struct?
  724. // A better question might be: can we run multiple instances of it?
  725. var (
  726. // network
  727. listeners []net.Listener
  728. clients = make(map[*client]bool)
  729. // IRC state
  730. // XXX: Beware that maps with identifier keys need to be indexed correctly.
  731. // We might want to enforce accessor functions for users and channels.
  732. started time.Time // when the server has been started
  733. users = make(map[string]*client) // maps nicknames to clients
  734. channels = make(map[string]*channel) // maps channel names to data
  735. whowas = make(map[string]*whowasInfo) // WHOWAS registry
  736. // event loop
  737. quitting bool
  738. quitTimer <-chan time.Time
  739. sigs = make(chan os.Signal, 1)
  740. conns = make(chan net.Conn)
  741. prepared = make(chan preparedEvent)
  742. reads = make(chan readEvent)
  743. writes = make(chan writeEvent)
  744. timers = make(chan func())
  745. // configuration
  746. config simpleConfig // server configuration
  747. tlsConf *tls.Config // TLS connection configuration
  748. serverName string // our server name
  749. pingInterval time.Duration // ping interval
  750. maxConnections int // max connections allowed or 0
  751. motd []string // MOTD (none if empty)
  752. catalog map[int]string // message catalog for server msgs
  753. operators map[string]bool // TLS certificate fingerprints for IRCops
  754. )
  755. // Forcefully tear down all connections.
  756. func forceQuit(reason string) {
  757. if !quitting {
  758. exitFatal("forceQuit called without initiateQuit")
  759. }
  760. printStatus("forced shutdown (%s)", reason)
  761. for c := range clients {
  762. // initiateQuit has already unregistered the client.
  763. c.kill("Shutting down")
  764. }
  765. }
  766. // Initiate a clean shutdown of the whole daemon.
  767. func initiateQuit() {
  768. printStatus("shutting down")
  769. for _, ln := range listeners {
  770. if err := ln.Close(); err != nil {
  771. printError("%s", err)
  772. }
  773. }
  774. for c := range clients {
  775. c.closeLink("Shutting down")
  776. }
  777. quitTimer = time.After(5 * time.Second)
  778. quitting = true
  779. }
  780. func ircChannelCreate(name string) *channel {
  781. ch := &channel{
  782. name: name,
  783. userLimit: -1,
  784. created: time.Now(),
  785. userModes: make(map[*client]uint),
  786. }
  787. channels[ircToCanon(name)] = ch
  788. return ch
  789. }
  790. func ircChannelDestroyIfEmpty(ch *channel) {
  791. if len(ch.userModes) == 0 {
  792. delete(channels, ircToCanon(ch.name))
  793. }
  794. }
  795. func ircNotifyRoommates(c *client, message string) {
  796. targets := make(map[*client]bool)
  797. for _, ch := range channels {
  798. _, present := ch.userModes[c]
  799. if !present || 0 != ch.modes&ircChanModeQuiet {
  800. continue
  801. }
  802. for client := range ch.userModes {
  803. targets[client] = true
  804. }
  805. }
  806. for roommate := range targets {
  807. if roommate != c {
  808. roommate.send(message)
  809. }
  810. }
  811. }
  812. // --- Clients (continued) -----------------------------------------------------
  813. func (c *client) printDebug(format string, args ...interface{}) {
  814. if debugMode {
  815. printDebug("(%s) %s", c.address, fmt.Sprintf(format, args...))
  816. }
  817. }
  818. func ircAppendClientModes(m uint, mode []byte) []byte {
  819. if 0 != m&ircUserModeInvisible {
  820. mode = append(mode, 'i')
  821. }
  822. if 0 != m&ircUserModeRxWallops {
  823. mode = append(mode, 'w')
  824. }
  825. if 0 != m&ircUserModeRestricted {
  826. mode = append(mode, 'r')
  827. }
  828. if 0 != m&ircUserModeOperator {
  829. mode = append(mode, 'o')
  830. }
  831. if 0 != m&ircUserModeRxServerNotices {
  832. mode = append(mode, 's')
  833. }
  834. return mode
  835. }
  836. func (c *client) getMode() string {
  837. var mode []byte
  838. if c.awayMessage != "" {
  839. mode = append(mode, 'a')
  840. }
  841. return string(ircAppendClientModes(c.mode, mode))
  842. }
  843. func (c *client) send(line string) {
  844. if c.conn == nil || c.closing {
  845. return
  846. }
  847. oldSendQLen := len(c.sendQ)
  848. // So far there's only one message tag we use, so we can do it simple;
  849. // note that a 1024-character limit applies to messages with tags on.
  850. if 0 != c.capsEnabled&ircCapServerTime {
  851. c.sendQ = time.Now().UTC().
  852. AppendFormat(c.sendQ, "@time=2006-01-02T15:04:05.000Z ")
  853. }
  854. bytes := []byte(line)
  855. if len(bytes) > ircMaxMessageLength {
  856. bytes = bytes[:ircMaxMessageLength]
  857. }
  858. c.printDebug("<- %s", bytes)
  859. // TODO: Kill the connection above some "SendQ" threshold (careful!)
  860. c.sendQ = append(c.sendQ, bytes...)
  861. c.sendQ = append(c.sendQ, "\r\n"...)
  862. c.flushSendQ()
  863. // Technically we haven't sent it yet but that's a minor detail
  864. c.nSentMessages++
  865. c.sentBytes += len(c.sendQ) - oldSendQLen
  866. }
  867. func (c *client) sendf(format string, a ...interface{}) {
  868. c.send(fmt.Sprintf(format, a...))
  869. }
  870. func (c *client) addToWhowas() {
  871. // Only keeping one entry for each nickname.
  872. // TODO: Make sure this list doesn't get too long, for example by
  873. // putting them in a linked list ordered by time.
  874. whowas[ircToCanon(c.nickname)] = newWhowasInfo(c)
  875. }
  876. func (c *client) nicknameOrStar() string {
  877. if c.nickname == "" {
  878. return "*"
  879. }
  880. return c.nickname
  881. }
  882. func (c *client) unregister(reason string) {
  883. if !c.registered {
  884. return
  885. }
  886. ircNotifyRoommates(c, fmt.Sprintf(":%s!%s@%s QUIT :%s",
  887. c.nickname, c.username, c.hostname, reason))
  888. // The QUIT message will take care of state on clients.
  889. for _, ch := range channels {
  890. delete(ch.userModes, c)
  891. ircChannelDestroyIfEmpty(ch)
  892. }
  893. c.addToWhowas()
  894. delete(users, ircToCanon(c.nickname))
  895. c.nickname = ""
  896. c.registered = false
  897. }
  898. // Close the connection and forget about the client.
  899. func (c *client) kill(reason string) {
  900. if reason == "" {
  901. c.unregister("Client exited")
  902. } else {
  903. c.unregister(reason)
  904. }
  905. c.printDebug("client destroyed (%s)", reason)
  906. // Try to send a "close notify" alert if the TLS object is ready,
  907. // otherwise just tear down the transport.
  908. if c.conn != nil {
  909. _ = c.conn.Close()
  910. } else {
  911. _ = c.transport.Close()
  912. }
  913. c.cancelTimers()
  914. delete(clients, c)
  915. }
  916. // Tear down the client connection, trying to do so in a graceful manner.
  917. func (c *client) closeLink(reason string) {
  918. // Let's just cut the connection, the client can try again later.
  919. // We also want to avoid accidentally writing to the socket before
  920. // address resolution has finished.
  921. if c.conn == nil {
  922. c.kill(reason)
  923. return
  924. }
  925. if c.closing {
  926. return
  927. }
  928. // We push an "ERROR" message to the write buffer and let the writer send
  929. // it, with some arbitrary timeout. The "closing" state makes sure
  930. // that a/ we ignore any successive messages, and b/ that the connection
  931. // is killed after the write buffer is transferred and emptied.
  932. // (Since we send this message, we don't need to call CloseWrite here.)
  933. c.sendf("ERROR :Closing link: %s[%s] (%s)",
  934. c.nicknameOrStar(), c.hostname /* TODO host IP? */, reason)
  935. c.closing = true
  936. c.unregister(reason)
  937. c.setKillTimer()
  938. }
  939. func (c *client) inMaskList(masks []string) bool {
  940. client := fmt.Sprintf("%s!%s@%s", c.nickname, c.username, c.hostname)
  941. for _, mask := range masks {
  942. if ircFnmatch(mask, client) {
  943. return true
  944. }
  945. }
  946. return false
  947. }
  948. func (c *client) getTLSCertFingerprint() string {
  949. if c.tls == nil {
  950. return ""
  951. }
  952. peerCerts := c.tls.ConnectionState().PeerCertificates
  953. if len(peerCerts) == 0 {
  954. return ""
  955. }
  956. hash := sha256.Sum256(peerCerts[0].Raw)
  957. return hex.EncodeToString(hash[:])
  958. }
  959. // --- Timers ------------------------------------------------------------------
  960. // Free the resources of timers that haven't fired yet and for timers that are
  961. // in between firing and being collected by the event loop, mark that the event
  962. // should not be acted upon.
  963. func (c *client) cancelTimers() {
  964. for _, timer := range []**time.Timer{
  965. &c.killTimer, &c.timeoutTimer, &c.pingTimer,
  966. } {
  967. if *timer != nil {
  968. (*timer).Stop()
  969. *timer = nil
  970. }
  971. }
  972. }
  973. // Arrange for a function to be called later from the main goroutine.
  974. func (c *client) setTimer(timer **time.Timer, delay time.Duration, cb func()) {
  975. c.cancelTimers()
  976. var identityCapture *time.Timer
  977. identityCapture = time.AfterFunc(delay, func() {
  978. timers <- func() {
  979. // The timer might have been cancelled or even replaced.
  980. // When the client is killed, this will be nil.
  981. if *timer == identityCapture {
  982. cb()
  983. }
  984. }
  985. })
  986. *timer = identityCapture
  987. }
  988. func (c *client) setKillTimer() {
  989. c.setTimer(&c.killTimer, pingInterval, func() {
  990. c.kill("Timeout")
  991. })
  992. }
  993. func (c *client) setTimeoutTimer() {
  994. c.setTimer(&c.timeoutTimer, pingInterval, func() {
  995. c.closeLink(fmt.Sprintf("Ping timeout: >%d seconds",
  996. pingInterval/time.Second))
  997. })
  998. }
  999. func (c *client) setPingTimer() {
  1000. c.setTimer(&c.pingTimer, pingInterval, func() {
  1001. c.sendf("PING :%s", serverName)
  1002. c.setTimeoutTimer()
  1003. })
  1004. }
  1005. // --- IRC command handling ----------------------------------------------------
  1006. func (c *client) makeReply(id int, ap ...interface{}) string {
  1007. s := fmt.Sprintf(":%s %03d %s ", serverName, id, c.nicknameOrStar())
  1008. if reply, ok := catalog[id]; ok {
  1009. return s + fmt.Sprintf(reply, ap...)
  1010. }
  1011. return s + fmt.Sprintf(defaultReplies[id], ap...)
  1012. }
  1013. // XXX: This way simple static analysis cannot typecheck the arguments, so we
  1014. // need to be careful.
  1015. func (c *client) sendReply(id int, args ...interface{}) {
  1016. c.send(c.makeReply(id, args...))
  1017. }
  1018. /// Send a space-separated list of words across as many replies as needed.
  1019. func (c *client) sendReplyVector(id int, items []string, args ...interface{}) {
  1020. common := c.makeReply(id, args...)
  1021. // We always send at least one message (there might be a client that
  1022. // expects us to send this message at least once).
  1023. if len(items) == 0 {
  1024. items = append(items, "")
  1025. }
  1026. for len(items) > 0 {
  1027. // If not even a single item fits in the limit (which may happen,
  1028. // in theory) it just gets cropped. We could also skip it.
  1029. reply := append([]byte(common), items[0]...)
  1030. items = items[1:]
  1031. // Append as many items as fits in a single message.
  1032. for len(items) > 0 &&
  1033. len(reply)+1+len(items[0]) <= ircMaxMessageLength {
  1034. reply = append(reply, ' ')
  1035. reply = append(reply, items[0]...)
  1036. items = items[1:]
  1037. }
  1038. c.send(string(reply))
  1039. }
  1040. }
  1041. func (c *client) sendMOTD() {
  1042. if len(motd) == 0 {
  1043. c.sendReply(ERR_NOMOTD)
  1044. return
  1045. }
  1046. c.sendReply(RPL_MOTDSTART, serverName)
  1047. for _, line := range motd {
  1048. c.sendReply(RPL_MOTD, line)
  1049. }
  1050. c.sendReply(RPL_ENDOFMOTD)
  1051. }
  1052. func (c *client) sendLUSERS() {
  1053. nUsers, nServices, nOpers, nUnknown := 0, 0, 0, 0
  1054. for c := range clients {
  1055. if c.registered {
  1056. nUsers++
  1057. } else {
  1058. nUnknown++
  1059. }
  1060. if 0 != c.mode&ircUserModeOperator {
  1061. nOpers++
  1062. }
  1063. }
  1064. nChannels := 0
  1065. for _, ch := range channels {
  1066. if 0 != ch.modes&ircChanModeSecret {
  1067. nChannels++
  1068. }
  1069. }
  1070. c.sendReply(RPL_LUSERCLIENT, nUsers, nServices, 1 /* servers total */)
  1071. if nOpers != 0 {
  1072. c.sendReply(RPL_LUSEROP, nOpers)
  1073. }
  1074. if nUnknown != 0 {
  1075. c.sendReply(RPL_LUSERUNKNOWN, nUnknown)
  1076. }
  1077. if nChannels != 0 {
  1078. c.sendReply(RPL_LUSERCHANNELS, nChannels)
  1079. }
  1080. c.sendReply(RPL_LUSERME, nUsers+nServices+nUnknown, 0 /* peer servers */)
  1081. }
  1082. func ircIsThisMe(target string) bool {
  1083. // Target servers can also be matched by their users
  1084. if ircFnmatch(target, serverName) {
  1085. return true
  1086. }
  1087. _, ok := users[ircToCanon(target)]
  1088. return ok
  1089. }
  1090. func (c *client) sendISUPPORT() {
  1091. // Only # channels, +e supported, +I supported, unlimited arguments to MODE.
  1092. c.sendReply(RPL_ISUPPORT, fmt.Sprintf("CHANTYPES=# EXCEPTS INVEX MODES"+
  1093. " TARGMAX=WHOIS:,LIST:,NAMES:,PRIVMSG:1,NOTICE:1,KICK:"+
  1094. " NICKLEN=%d CHANNELLEN=%d", ircMaxNickname, ircMaxChannelName))
  1095. }
  1096. func (c *client) tryFinishRegistration() {
  1097. if c.registered || c.capNegotiating {
  1098. return
  1099. }
  1100. if c.nickname == "" || c.username == "" {
  1101. return
  1102. }
  1103. c.registered = true
  1104. c.sendReply(RPL_WELCOME, c.nickname, c.username, c.hostname)
  1105. c.sendReply(RPL_YOURHOST, serverName, projectVersion)
  1106. // The purpose of this message eludes me.
  1107. c.sendReply(RPL_CREATED, started.Format("Mon, 02 Jan 2006"))
  1108. c.sendReply(RPL_MYINFO, serverName, projectVersion,
  1109. ircSupportedUserModes, ircSupportedChanModes)
  1110. c.sendISUPPORT()
  1111. c.sendLUSERS()
  1112. c.sendMOTD()
  1113. if mode := c.getMode(); mode != "" {
  1114. c.sendf(":%s MODE %s :+%s", c.nickname, c.nickname, mode)
  1115. }
  1116. c.tlsCertFingerprint = c.getTLSCertFingerprint()
  1117. if c.tlsCertFingerprint != "" {
  1118. c.sendf(":%s NOTICE %s :Your TLS client certificate fingerprint is %s",
  1119. serverName, c.nickname, c.tlsCertFingerprint)
  1120. }
  1121. delete(whowas, ircToCanon(c.nickname))
  1122. }
  1123. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1124. // IRCv3 capability negotiation. See http://ircv3.org for details.
  1125. type ircCapArgs struct {
  1126. subcommand string // the subcommand being processed
  1127. fullParams string // whole parameter string
  1128. params []string // split parameters
  1129. target string // target parameter for replies
  1130. }
  1131. var ircCapTable = []struct {
  1132. flag uint // flag
  1133. name string // name of the capability
  1134. }{
  1135. {ircCapMultiPrefix, "multi-prefix"},
  1136. {ircCapInviteNotify, "invite-notify"},
  1137. {ircCapEchoMessage, "echo-message"},
  1138. {ircCapUserhostInNames, "userhost-in-names"},
  1139. {ircCapServerTime, "server-time"},
  1140. }
  1141. func (c *client) handleCAPLS(a *ircCapArgs) {
  1142. if len(a.params) == 1 {
  1143. if ver, err := strconv.ParseUint(a.params[0], 10, 32); err != nil {
  1144. c.sendReply(ERR_INVALIDCAPCMD, a.subcommand,
  1145. "Ignoring invalid protocol version number")
  1146. } else {
  1147. c.capVersion = uint(ver)
  1148. }
  1149. }
  1150. c.capNegotiating = true
  1151. c.sendf(":%s CAP %s LS :multi-prefix invite-notify echo-message"+
  1152. " userhost-in-names server-time", serverName, a.target)
  1153. }
  1154. func (c *client) handleCAPLIST(a *ircCapArgs) {
  1155. caps := []string{}
  1156. for _, cap := range ircCapTable {
  1157. if 0 != c.capsEnabled&cap.flag {
  1158. caps = append(caps, cap.name)
  1159. }
  1160. }
  1161. c.sendf(":%s CAP %s LIST :%s", serverName, a.target,
  1162. strings.Join(caps, " "))
  1163. }
  1164. func ircDecodeCapability(name string) uint {
  1165. for _, cap := range ircCapTable {
  1166. if cap.name == name {
  1167. return cap.flag
  1168. }
  1169. }
  1170. return 0
  1171. }
  1172. func (c *client) handleCAPREQ(a *ircCapArgs) {
  1173. c.capNegotiating = true
  1174. newCaps := c.capsEnabled
  1175. ok := true
  1176. for _, param := range a.params {
  1177. removing := false
  1178. name := param
  1179. if name[:1] == "-" {
  1180. removing = true
  1181. name = name[1:]
  1182. }
  1183. if cap := ircDecodeCapability(name); cap == 0 {
  1184. ok = false
  1185. } else if removing {
  1186. newCaps &= ^cap
  1187. } else {
  1188. newCaps |= cap
  1189. }
  1190. }
  1191. if ok {
  1192. c.capsEnabled = newCaps
  1193. c.sendf(":%s CAP %s ACK :%s", serverName, a.target, a.fullParams)
  1194. } else {
  1195. c.sendf(":%s CAP %s NAK :%s", serverName, a.target, a.fullParams)
  1196. }
  1197. }
  1198. func (c *client) handleCAPACK(a *ircCapArgs) {
  1199. if len(a.params) > 0 {
  1200. c.sendReply(ERR_INVALIDCAPCMD, a.subcommand,
  1201. "No acknowledgable capabilities supported")
  1202. }
  1203. }
  1204. func (c *client) handleCAPEND(a *ircCapArgs) {
  1205. c.capNegotiating = false
  1206. c.tryFinishRegistration()
  1207. }
  1208. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1209. var ircCapHandlers = map[string]func(*client, *ircCapArgs){
  1210. "LS": (*client).handleCAPLS,
  1211. "LIST": (*client).handleCAPLIST,
  1212. "REQ": (*client).handleCAPREQ,
  1213. "ACK": (*client).handleCAPACK,
  1214. "END": (*client).handleCAPEND,
  1215. }
  1216. // XXX: Maybe these also deserve to be methods for client? They operate on
  1217. // global state, though.
  1218. func ircHandleCAP(msg *message, c *client) {
  1219. if len(msg.params) < 1 {
  1220. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  1221. return
  1222. }
  1223. args := &ircCapArgs{
  1224. target: c.nicknameOrStar(),
  1225. subcommand: msg.params[0],
  1226. fullParams: "",
  1227. params: []string{},
  1228. }
  1229. if len(msg.params) > 1 {
  1230. args.fullParams = msg.params[1]
  1231. args.params = splitString(args.fullParams, " ", true)
  1232. }
  1233. if fn, ok := ircCapHandlers[ircToCanon(args.subcommand)]; !ok {
  1234. c.sendReply(ERR_INVALIDCAPCMD, args.subcommand,
  1235. "Invalid CAP subcommand")
  1236. } else {
  1237. fn(c, args)
  1238. }
  1239. }
  1240. func ircHandlePASS(msg *message, c *client) {
  1241. if c.registered {
  1242. c.sendReply(ERR_ALREADYREGISTERED)
  1243. } else if len(msg.params) < 1 {
  1244. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  1245. }
  1246. // We have TLS client certificates for this purpose; ignoring.
  1247. }
  1248. func ircHandleNICK(msg *message, c *client) {
  1249. if len(msg.params) < 1 {
  1250. c.sendReply(ERR_NONICKNAMEGIVEN)
  1251. return
  1252. }
  1253. nickname := msg.params[0]
  1254. if !ircIsValidNickname(nickname) {
  1255. c.sendReply(ERR_ERRONEOUSNICKNAME, nickname)
  1256. return
  1257. }
  1258. nicknameCanon := ircToCanon(nickname)
  1259. if client, ok := users[nicknameCanon]; ok && client != c {
  1260. c.sendReply(ERR_NICKNAMEINUSE, nickname)
  1261. return
  1262. }
  1263. if c.registered {
  1264. c.addToWhowas()
  1265. message := fmt.Sprintf(":%s!%s@%s NICK :%s",
  1266. c.nickname, c.username, c.hostname, nickname)
  1267. ircNotifyRoommates(c, message)
  1268. c.send(message)
  1269. }
  1270. // Release the old nickname and allocate a new one.
  1271. if c.nickname != "" {
  1272. delete(users, ircToCanon(c.nickname))
  1273. }
  1274. c.nickname = nickname
  1275. users[nicknameCanon] = c
  1276. c.tryFinishRegistration()
  1277. }
  1278. func ircHandleUSER(msg *message, c *client) {
  1279. if c.registered {
  1280. c.sendReply(ERR_ALREADYREGISTERED)
  1281. return
  1282. }
  1283. if len(msg.params) < 4 {
  1284. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  1285. return
  1286. }
  1287. username, mode, realname := msg.params[0], msg.params[1], msg.params[3]
  1288. // Unfortunately, the protocol doesn't give us any means of rejecting it.
  1289. if !ircIsValidUsername(username) {
  1290. username = "*"
  1291. }
  1292. c.username = username
  1293. c.realname = realname
  1294. c.mode = 0
  1295. if m, err := strconv.ParseUint(mode, 10, 32); err != nil {
  1296. if 0 != m&4 {
  1297. c.mode |= ircUserModeRxWallops
  1298. }
  1299. if 0 != m&8 {
  1300. c.mode |= ircUserModeInvisible
  1301. }
  1302. }
  1303. c.tryFinishRegistration()
  1304. }
  1305. func ircHandleUSERHOST(msg *message, c *client) {
  1306. if len(msg.params) < 1 {
  1307. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  1308. return
  1309. }
  1310. var reply []byte
  1311. for i := 0; i < 5 && i < len(msg.params); i++ {
  1312. nick := msg.params[i]
  1313. target := users[ircToCanon(nick)]
  1314. if target == nil {
  1315. continue
  1316. }
  1317. if i != 0 {
  1318. reply = append(reply, ' ')
  1319. }
  1320. reply = append(reply, nick...)
  1321. if 0 != target.mode&ircUserModeOperator {
  1322. reply = append(reply, '*')
  1323. }
  1324. if target.awayMessage != "" {
  1325. reply = append(reply, "=-"...)
  1326. } else {
  1327. reply = append(reply, "=+"...)
  1328. }
  1329. reply = append(reply, (target.username + "@" + target.hostname)...)
  1330. }
  1331. c.sendReply(RPL_USERHOST, string(reply))
  1332. }
  1333. func ircHandleLUSERS(msg *message, c *client) {
  1334. if len(msg.params) > 1 && !ircIsThisMe(msg.params[1]) {
  1335. c.sendReply(ERR_NOSUCHSERVER, msg.params[1])
  1336. return
  1337. }
  1338. c.sendLUSERS()
  1339. }
  1340. func ircHandleMOTD(msg *message, c *client) {
  1341. if len(msg.params) > 0 && !ircIsThisMe(msg.params[0]) {
  1342. c.sendReply(ERR_NOSUCHSERVER, msg.params[1])
  1343. return
  1344. }
  1345. c.sendMOTD()
  1346. }
  1347. func ircHandlePING(msg *message, c *client) {
  1348. // XXX: The RFC is pretty incomprehensible about the exact usage.
  1349. if len(msg.params) > 1 && !ircIsThisMe(msg.params[1]) {
  1350. c.sendReply(ERR_NOSUCHSERVER, msg.params[1])
  1351. } else if len(msg.params) < 1 {
  1352. c.sendReply(ERR_NOORIGIN)
  1353. } else {
  1354. c.sendf(":%s PONG :%s", serverName, msg.params[0])
  1355. }
  1356. }
  1357. func ircHandlePONG(msg *message, c *client) {
  1358. // We are the only server, so we don't have to care too much.
  1359. if len(msg.params) < 1 {
  1360. c.sendReply(ERR_NOORIGIN)
  1361. return
  1362. }
  1363. // Set a new timer to send another PING
  1364. c.setPingTimer()
  1365. }
  1366. func ircHandleQUIT(msg *message, c *client) {
  1367. reason := c.nickname
  1368. if len(msg.params) > 0 {
  1369. reason = msg.params[0]
  1370. }
  1371. c.closeLink("Quit: " + reason)
  1372. }
  1373. func ircHandleTIME(msg *message, c *client) {
  1374. if len(msg.params) > 0 && !ircIsThisMe(msg.params[0]) {
  1375. c.sendReply(ERR_NOSUCHSERVER, msg.params[0])
  1376. return
  1377. }
  1378. c.sendReply(RPL_TIME, serverName,
  1379. time.Now().Format("Mon Jan _2 2006 15:04:05"))
  1380. }
  1381. func ircHandleVERSION(msg *message, c *client) {
  1382. if len(msg.params) > 0 && !ircIsThisMe(msg.params[0]) {
  1383. c.sendReply(ERR_NOSUCHSERVER, msg.params[0])
  1384. return
  1385. }
  1386. postVersion := 0
  1387. if debugMode {
  1388. postVersion = 1
  1389. }
  1390. c.sendReply(RPL_VERSION, projectVersion, postVersion, serverName,
  1391. projectName+" "+projectVersion)
  1392. c.sendISUPPORT()
  1393. }
  1394. func ircChannelMulticast(ch *channel, msg string, except *client) {
  1395. for c := range ch.userModes {
  1396. if c != except {
  1397. c.send(msg)
  1398. }
  1399. }
  1400. }
  1401. func ircModifyMode(mask *uint, mode uint, add bool) bool {
  1402. orig := *mask
  1403. if add {
  1404. *mask |= mode
  1405. } else {
  1406. *mask &= ^mode
  1407. }
  1408. return *mask != orig
  1409. }
  1410. func ircUpdateUserMode(c *client, newMode uint) {
  1411. oldMode := c.mode
  1412. c.mode = newMode
  1413. added, removed := newMode & ^oldMode, oldMode & ^newMode
  1414. var diff []byte
  1415. if added != 0 {
  1416. diff = append(diff, '+')
  1417. diff = ircAppendClientModes(added, diff)
  1418. }
  1419. if removed != 0 {
  1420. diff = append(diff, '-')
  1421. diff = ircAppendClientModes(removed, diff)
  1422. }
  1423. if len(diff) > 0 {
  1424. c.sendf(":%s MODE %s :%s", c.nickname, c.nickname, string(diff))
  1425. }
  1426. }
  1427. func ircHandleUserModeChange(c *client, modeString string) {
  1428. newMode := c.mode
  1429. adding := true
  1430. for _, flag := range modeString {
  1431. switch flag {
  1432. case '+':
  1433. adding = true
  1434. case '-':
  1435. adding = false
  1436. case 'a':
  1437. // Ignore, the client should use AWAY.
  1438. case 'i':
  1439. ircModifyMode(&newMode, ircUserModeInvisible, adding)
  1440. case 'w':
  1441. ircModifyMode(&newMode, ircUserModeRxWallops, adding)
  1442. case 'r':
  1443. // It's not possible ot un-restrict yourself.
  1444. if adding {
  1445. newMode |= ircUserModeRestricted
  1446. }
  1447. case 'o':
  1448. if !adding {
  1449. newMode &= ^ircUserModeOperator
  1450. } else if operators[c.tlsCertFingerprint] {
  1451. newMode |= ircUserModeOperator
  1452. } else {
  1453. c.sendf(":%s NOTICE %s :Either you're not using an TLS"+
  1454. " client certificate, or the fingerprint doesn't match",
  1455. serverName, c.nickname)
  1456. }
  1457. case 's':
  1458. ircModifyMode(&newMode, ircUserModeRxServerNotices, adding)
  1459. default:
  1460. c.sendReply(ERR_UMODEUNKNOWNFLAG)
  1461. return
  1462. }
  1463. }
  1464. ircUpdateUserMode(c, newMode)
  1465. }
  1466. func ircSendChannelList(c *client, channelName string, list []string,
  1467. reply, endReply int) {
  1468. for _, line := range list {
  1469. c.sendReply(reply, channelName, line)
  1470. }
  1471. c.sendReply(endReply, channelName)
  1472. }
  1473. func ircCheckExpandUserMask(mask string) string {
  1474. var result []byte
  1475. result = append(result, mask...)
  1476. // Make sure it is a complete mask.
  1477. if bytes.IndexByte(result, '!') < 0 {
  1478. result = append(result, "!*"...)
  1479. }
  1480. if bytes.IndexByte(result, '@') < 0 {
  1481. result = append(result, "@*"...)
  1482. }
  1483. // And validate whatever the result is.
  1484. s := string(result)
  1485. if !ircIsValidUserMask(s) {
  1486. return ""
  1487. }
  1488. return s
  1489. }
  1490. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1491. // Channel MODE command handling. This is by far the worst command to implement
  1492. // from the whole RFC; don't blame me if it doesn't work exactly as expected.
  1493. type modeProcessor struct {
  1494. params []string // mode string parameters
  1495. c *client // who does the changes
  1496. ch *channel // the channel we're modifying
  1497. present bool // c present on ch
  1498. modes uint // channel user modes
  1499. adding bool // currently adding modes
  1500. modeChar byte // currently processed mode char
  1501. added []byte // added modes
  1502. removed []byte // removed modes
  1503. output *[]byte // "added" or "removed"
  1504. addedParams []string // params for added modes
  1505. removedParams []string // params for removed modes
  1506. outputParams *[]string // "addedParams" or "removedParams"
  1507. }
  1508. func (mp *modeProcessor) nextParam() string {
  1509. if len(mp.params) == 0 {
  1510. return ""
  1511. }
  1512. param := mp.params[0]
  1513. mp.params = mp.params[1:]
  1514. return param
  1515. }
  1516. func (mp *modeProcessor) checkOperator() bool {
  1517. if (mp.present && 0 != mp.modes&ircChanModeOperator) ||
  1518. 0 != mp.c.mode&ircUserModeOperator {
  1519. return true
  1520. }
  1521. mp.c.sendReply(ERR_CHANOPRIVSNEEDED, mp.ch.name)
  1522. return false
  1523. }
  1524. func (mp *modeProcessor) doUser(mode uint) {
  1525. target := mp.nextParam()
  1526. if !mp.checkOperator() || target == "" {
  1527. return
  1528. }
  1529. if client := users[ircToCanon(target)]; client == nil {
  1530. mp.c.sendReply(ERR_NOSUCHNICK, target)
  1531. } else if modes, present := mp.ch.userModes[client]; !present {
  1532. mp.c.sendReply(ERR_USERNOTINCHANNEL, target, mp.ch.name)
  1533. } else if ircModifyMode(&modes, mode, mp.adding) {
  1534. mp.ch.userModes[client] = modes
  1535. *mp.output = append(*mp.output, mp.modeChar)
  1536. *mp.outputParams = append(*mp.outputParams, client.nickname)
  1537. }
  1538. }
  1539. func (mp *modeProcessor) doChan(mode uint) bool {
  1540. if !mp.checkOperator() || !ircModifyMode(&mp.ch.modes, mode, mp.adding) {
  1541. return false
  1542. }
  1543. *mp.output = append(*mp.output, mp.modeChar)
  1544. return true
  1545. }
  1546. func (mp *modeProcessor) doChanRemove(modeChar byte, mode uint) {
  1547. if mp.adding && ircModifyMode(&mp.ch.modes, mode, false) {
  1548. mp.removed = append(mp.removed, modeChar)
  1549. }
  1550. }
  1551. func (mp *modeProcessor) doList(list *[]string, listMsg, endMsg int) {
  1552. target := mp.nextParam()
  1553. if target == "" {
  1554. if mp.adding {
  1555. ircSendChannelList(mp.c, mp.ch.name, *list, listMsg, endMsg)
  1556. }
  1557. return
  1558. }
  1559. if !mp.checkOperator() {
  1560. return
  1561. }
  1562. mask := ircCheckExpandUserMask(target)
  1563. if mask == "" {
  1564. return
  1565. }
  1566. var i int
  1567. for i = 0; i < len(*list); i++ {
  1568. if ircEqual((*list)[i], mask) {
  1569. break
  1570. }
  1571. }
  1572. found := i < len(*list)
  1573. if found != mp.adding {
  1574. if mp.adding {
  1575. *list = append(*list, mask)
  1576. } else {
  1577. *list = append((*list)[:i], (*list)[i+1:]...)
  1578. }
  1579. *mp.output = append(*mp.output, mp.modeChar)
  1580. *mp.outputParams = append(*mp.outputParams, mask)
  1581. }
  1582. }
  1583. func (mp *modeProcessor) doKey() {
  1584. target := mp.nextParam()
  1585. if !mp.checkOperator() || target == "" {
  1586. return
  1587. }
  1588. if !mp.adding {
  1589. if mp.ch.key == "" || !ircEqual(target, mp.ch.key) {
  1590. return
  1591. }
  1592. mp.removed = append(mp.removed, mp.modeChar)
  1593. mp.removedParams = append(mp.removedParams, mp.ch.key)
  1594. mp.ch.key = ""
  1595. } else if !ircIsValidKey(target) {
  1596. // TODO: We should notify the user somehow.
  1597. return
  1598. } else if mp.ch.key != "" {
  1599. mp.c.sendReply(ERR_KEYSET, mp.ch.name)
  1600. } else {
  1601. mp.ch.key = target
  1602. mp.added = append(mp.added, mp.modeChar)
  1603. mp.addedParams = append(mp.addedParams, mp.ch.key)
  1604. }
  1605. }
  1606. func (mp *modeProcessor) doLimit() {
  1607. if !mp.checkOperator() {
  1608. return
  1609. }
  1610. if !mp.adding {
  1611. if mp.ch.userLimit == -1 {
  1612. return
  1613. }
  1614. mp.ch.userLimit = -1
  1615. mp.removed = append(mp.removed, mp.modeChar)
  1616. } else if target := mp.nextParam(); target != "" {
  1617. if x, err := strconv.ParseInt(target, 10, 32); err == nil && x > 0 {
  1618. mp.ch.userLimit = int(x)
  1619. mp.added = append(mp.added, mp.modeChar)
  1620. mp.addedParams = append(mp.addedParams, target)
  1621. }
  1622. }
  1623. }
  1624. func (mp *modeProcessor) step(modeChar byte) bool {
  1625. mp.modeChar = modeChar
  1626. switch mp.modeChar {
  1627. case '+':
  1628. mp.adding = true
  1629. mp.output = &mp.added
  1630. mp.outputParams = &mp.addedParams
  1631. case '-':
  1632. mp.adding = false
  1633. mp.output = &mp.removed
  1634. mp.outputParams = &mp.removedParams
  1635. case 'o':
  1636. mp.doUser(ircChanModeOperator)
  1637. case 'v':
  1638. mp.doUser(ircChanModeVoice)
  1639. case 'i':
  1640. mp.doChan(ircChanModeInviteOnly)
  1641. case 'm':
  1642. mp.doChan(ircChanModeModerated)
  1643. case 'n':
  1644. mp.doChan(ircChanModeNoOutsideMsgs)
  1645. case 'q':
  1646. mp.doChan(ircChanModeQuiet)
  1647. case 't':
  1648. mp.doChan(ircChanModeProtectedTopic)
  1649. case 'p':
  1650. if mp.doChan(ircChanModePrivate) {
  1651. mp.doChanRemove('s', ircChanModeSecret)
  1652. }
  1653. case 's':
  1654. if mp.doChan(ircChanModeSecret) {
  1655. mp.doChanRemove('p', ircChanModePrivate)
  1656. }
  1657. case 'b':
  1658. mp.doList(&mp.ch.banList, RPL_BANLIST, RPL_ENDOFBANLIST)
  1659. case 'e':
  1660. mp.doList(&mp.ch.banList, RPL_EXCEPTLIST, RPL_ENDOFEXCEPTLIST)
  1661. case 'I':
  1662. mp.doList(&mp.ch.banList, RPL_INVITELIST, RPL_ENDOFINVITELIST)
  1663. case 'k':
  1664. mp.doKey()
  1665. case 'l':
  1666. mp.doLimit()
  1667. default:
  1668. // It's not safe to continue, results could be undesired.
  1669. mp.c.sendReply(ERR_UNKNOWNMODE, modeChar, mp.ch.name)
  1670. return false
  1671. }
  1672. return true
  1673. }
  1674. func ircHandleChanModeChange(c *client, ch *channel, params []string) {
  1675. modes, present := ch.userModes[c]
  1676. mp := &modeProcessor{
  1677. c: c,
  1678. ch: ch,
  1679. present: present,
  1680. modes: modes,
  1681. params: params,
  1682. }
  1683. Outer:
  1684. for {
  1685. modeString := mp.nextParam()
  1686. if modeString == "" {
  1687. break
  1688. }
  1689. mp.step('+')
  1690. for _, modeChar := range []byte(modeString) {
  1691. if !mp.step(modeChar) {
  1692. break Outer
  1693. }
  1694. }
  1695. }
  1696. // TODO: Limit to three changes with parameter per command.
  1697. if len(mp.added) > 0 || len(mp.removed) > 0 {
  1698. buf := []byte(fmt.Sprintf(":%s!%s@%s MODE %s ",
  1699. mp.c.nickname, mp.c.username, mp.c.hostname, mp.ch.name))
  1700. if len(mp.added) > 0 {
  1701. buf = append(buf, '+')
  1702. buf = append(buf, mp.added...)
  1703. }
  1704. if len(mp.removed) > 0 {
  1705. buf = append(buf, '-')
  1706. buf = append(buf, mp.removed...)
  1707. }
  1708. for _, param := range mp.addedParams {
  1709. buf = append(buf, ' ')
  1710. buf = append(buf, param...)
  1711. }
  1712. for _, param := range mp.removedParams {
  1713. buf = append(buf, ' ')
  1714. buf = append(buf, param...)
  1715. }
  1716. ircChannelMulticast(mp.ch, string(buf), nil)
  1717. }
  1718. }
  1719. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1720. func ircHandleMODE(msg *message, c *client) {
  1721. if len(msg.params) < 1 {
  1722. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  1723. return
  1724. }
  1725. target := msg.params[0]
  1726. client := users[ircToCanon(target)]
  1727. ch := channels[ircToCanon(target)]
  1728. if client != nil {
  1729. if !ircEqual(target, c.nickname) {
  1730. c.sendReply(ERR_USERSDONTMATCH)
  1731. return
  1732. }
  1733. if len(msg.params) < 2 {
  1734. c.sendReply(RPL_UMODEIS, c.getMode())
  1735. } else {
  1736. ircHandleUserModeChange(c, msg.params[1])
  1737. }
  1738. } else if ch != nil {
  1739. if len(msg.params) < 2 {
  1740. _, present := ch.userModes[c]
  1741. c.sendReply(RPL_CHANNELMODEIS, target, ch.getMode(present))
  1742. c.sendReply(RPL_CREATIONTIME, target, ch.created.Unix())
  1743. } else {
  1744. ircHandleChanModeChange(c, ch, msg.params[1:])
  1745. }
  1746. } else {
  1747. c.sendReply(ERR_NOSUCHNICK, target)
  1748. }
  1749. }
  1750. func ircHandleUserMessage(msg *message, c *client,
  1751. command string, allowAwayReply bool) {
  1752. if len(msg.params) < 1 {
  1753. c.sendReply(ERR_NORECIPIENT, msg.command)
  1754. return
  1755. }
  1756. if len(msg.params) < 2 || msg.params[1] == "" {
  1757. c.sendReply(ERR_NOTEXTTOSEND)
  1758. return
  1759. }
  1760. target, text := msg.params[0], msg.params[1]
  1761. message := fmt.Sprintf(":%s!%s@%s %s %s :%s",
  1762. c.nickname, c.username, c.hostname, command, target, text)
  1763. if client := users[ircToCanon(target)]; client != nil {
  1764. client.send(message)
  1765. if allowAwayReply && client.awayMessage != "" {
  1766. c.sendReply(RPL_AWAY, target, client.awayMessage)
  1767. }
  1768. // Acknowledging a message from the client to itself would be silly.
  1769. if client != c && (0 != c.capsEnabled&ircCapEchoMessage) {
  1770. c.send(message)
  1771. }
  1772. } else if ch := channels[ircToCanon(target)]; ch != nil {
  1773. modes, present := ch.userModes[c]
  1774. outsider := !present && 0 != ch.modes&ircChanModeNoOutsideMsgs
  1775. moderated := 0 != ch.modes&ircChanModeModerated &&
  1776. 0 == modes&(ircChanModeVoice|ircChanModeOperator)
  1777. banned := c.inMaskList(ch.banList) && !c.inMaskList(ch.exceptionList)
  1778. if outsider || moderated || banned {
  1779. c.sendReply(ERR_CANNOTSENDTOCHAN, target)
  1780. return
  1781. }
  1782. except := c
  1783. if 0 != c.capsEnabled&ircCapEchoMessage {
  1784. except = nil
  1785. }
  1786. ircChannelMulticast(ch, message, except)
  1787. } else {
  1788. c.sendReply(ERR_NOSUCHNICK, target)
  1789. }
  1790. }
  1791. func ircHandlePRIVMSG(msg *message, c *client) {
  1792. ircHandleUserMessage(msg, c, "PRIVMSG", true /* allowAwayReply */)
  1793. c.lastActive = time.Now()
  1794. }
  1795. func ircHandleNOTICE(msg *message, c *client) {
  1796. ircHandleUserMessage(msg, c, "NOTICE", false /* allowAwayReply */)
  1797. }
  1798. func ircHandleLIST(msg *message, c *client) {
  1799. if len(msg.params) > 1 && !ircIsThisMe(msg.params[1]) {
  1800. c.sendReply(ERR_NOSUCHSERVER, msg.params[1])
  1801. return
  1802. }
  1803. // XXX: Maybe we should skip ircUserModeInvisible from user counts.
  1804. if len(msg.params) == 0 {
  1805. for _, ch := range channels {
  1806. if _, present := ch.userModes[c]; present ||
  1807. 0 == ch.modes&(ircChanModePrivate|ircChanModeSecret) {
  1808. c.sendReply(RPL_LIST, ch.name, len(ch.userModes), ch.topic)
  1809. }
  1810. }
  1811. } else {
  1812. for _, target := range splitString(msg.params[0], ",", true) {
  1813. if ch := channels[ircToCanon(target)]; ch != nil &&
  1814. 0 == ch.modes&ircChanModeSecret {
  1815. c.sendReply(RPL_LIST, ch.name, len(ch.userModes), ch.topic)
  1816. }
  1817. }
  1818. }
  1819. c.sendReply(RPL_LISTEND)
  1820. }
  1821. func ircAppendPrefixes(c *client, modes uint, buf []byte) []byte {
  1822. var all []byte
  1823. if 0 != modes&ircChanModeOperator {
  1824. all = append(all, '@')
  1825. }
  1826. if 0 != modes&ircChanModeVoice {
  1827. all = append(all, '+')
  1828. }
  1829. if len(all) > 0 {
  1830. if 0 != c.capsEnabled&ircCapMultiPrefix {
  1831. buf = append(buf, all...)
  1832. } else {
  1833. buf = append(buf, all[0])
  1834. }
  1835. }
  1836. return buf
  1837. }
  1838. func ircMakeRPLNAMREPLYItem(c, target *client, modes uint) string {
  1839. result := string(ircAppendPrefixes(c, modes, nil)) + target.nickname
  1840. if 0 != c.capsEnabled&ircCapUserhostInNames {
  1841. result += fmt.Sprintf("!%s@%s", target.username, target.hostname)
  1842. }
  1843. return result
  1844. }
  1845. func ircSendRPLNAMREPLY(c *client, ch *channel, usedNicks map[*client]bool) {
  1846. kind := '='
  1847. if 0 != ch.modes&ircChanModeSecret {
  1848. kind = '@'
  1849. } else if 0 != ch.modes&ircChanModePrivate {
  1850. kind = '*'
  1851. }
  1852. _, present := ch.userModes[c]
  1853. var nicks []string
  1854. for client, modes := range ch.userModes {
  1855. if !present && 0 != client.mode&ircUserModeInvisible {
  1856. continue
  1857. }
  1858. if usedNicks != nil {
  1859. usedNicks[client] = true
  1860. }
  1861. nicks = append(nicks, ircMakeRPLNAMREPLYItem(c, client, modes))
  1862. }
  1863. c.sendReplyVector(RPL_NAMREPLY, nicks, kind, ch.name, "")
  1864. }
  1865. func ircSendDisassociatedNames(c *client, usedNicks map[*client]bool) {
  1866. var nicks []string
  1867. for _, client := range users {
  1868. if 0 == client.mode&ircUserModeInvisible && !usedNicks[client] {
  1869. nicks = append(nicks, ircMakeRPLNAMREPLYItem(c, client, 0))
  1870. }
  1871. }
  1872. if len(nicks) > 0 {
  1873. c.sendReplyVector(RPL_NAMREPLY, nicks, '*', "*", "")
  1874. }
  1875. }
  1876. func ircHandleNAMES(msg *message, c *client) {
  1877. if len(msg.params) > 1 && !ircIsThisMe(msg.params[1]) {
  1878. c.sendReply(ERR_NOSUCHSERVER, msg.params[1])
  1879. return
  1880. }
  1881. if len(msg.params) == 0 {
  1882. usedNicks := make(map[*client]bool)
  1883. for _, ch := range channels {
  1884. if _, present := ch.userModes[c]; present ||
  1885. 0 == ch.modes&(ircChanModePrivate|ircChanModeSecret) {
  1886. ircSendRPLNAMREPLY(c, ch, usedNicks)
  1887. }
  1888. }
  1889. // Also send all visible users we haven't listed yet.
  1890. ircSendDisassociatedNames(c, usedNicks)
  1891. c.sendReply(RPL_ENDOFNAMES, "*")
  1892. } else {
  1893. for _, target := range splitString(msg.params[0], ",", true) {
  1894. if ch := channels[ircToCanon(target)]; ch == nil {
  1895. } else if _, present := ch.userModes[c]; present ||
  1896. 0 == ch.modes&ircChanModeSecret {
  1897. ircSendRPLNAMREPLY(c, ch, nil)
  1898. c.sendReply(RPL_ENDOFNAMES, target)
  1899. }
  1900. }
  1901. }
  1902. }
  1903. func ircSendRPLWHOREPLY(c *client, ch *channel, target *client) {
  1904. var chars []byte
  1905. if target.awayMessage != "" {
  1906. chars = append(chars, 'G')
  1907. } else {
  1908. chars = append(chars, 'H')
  1909. }
  1910. if 0 != target.mode&ircUserModeOperator {
  1911. chars = append(chars, '*')
  1912. }
  1913. channelName := "*"
  1914. if ch != nil {
  1915. channelName = ch.name
  1916. if modes, present := ch.userModes[target]; present {
  1917. chars = ircAppendPrefixes(c, modes, chars)
  1918. }
  1919. }
  1920. c.sendReply(RPL_WHOREPLY, channelName,
  1921. target.username, target.hostname, serverName,
  1922. target.nickname, string(chars), 0 /* hop count */, target.realname)
  1923. }
  1924. func ircMatchSendRPLWHOREPLY(c, target *client, mask string) {
  1925. isRoommate := false
  1926. for _, ch := range channels {
  1927. _, presentClient := ch.userModes[c]
  1928. _, presentTarget := ch.userModes[target]
  1929. if presentClient && presentTarget {
  1930. isRoommate = true
  1931. break
  1932. }
  1933. }
  1934. if !isRoommate && 0 != target.mode&ircUserModeInvisible {
  1935. return
  1936. }
  1937. if !ircFnmatch(mask, target.hostname) &&
  1938. !ircFnmatch(mask, target.nickname) &&
  1939. !ircFnmatch(mask, target.realname) &&
  1940. !ircFnmatch(mask, serverName) {
  1941. return
  1942. }
  1943. // Try to find a channel they're on that's visible to us.
  1944. var userCh *channel
  1945. for _, ch := range channels {
  1946. _, presentClient := ch.userModes[c]
  1947. _, presentTarget := ch.userModes[target]
  1948. if presentTarget && (presentClient ||
  1949. 0 == ch.modes&(ircChanModePrivate|ircChanModeSecret)) {
  1950. userCh = ch
  1951. break
  1952. }
  1953. }
  1954. ircSendRPLWHOREPLY(c, userCh, target)
  1955. }
  1956. func ircHandleWHO(msg *message, c *client) {
  1957. onlyOps := len(msg.params) > 1 && msg.params[1] == "o"
  1958. shownMask, usedMask := "*", "*"
  1959. if len(msg.params) > 0 {
  1960. shownMask = msg.params[0]
  1961. if shownMask != "0" {
  1962. usedMask = shownMask
  1963. }
  1964. }
  1965. if ch := channels[ircToCanon(usedMask)]; ch != nil {
  1966. _, present := ch.userModes[c]
  1967. if present || 0 == ch.modes&ircChanModeSecret {
  1968. for client := range ch.userModes {
  1969. if (present || 0 == client.mode&ircUserModeInvisible) &&
  1970. (!onlyOps || 0 != client.mode&ircUserModeOperator) {
  1971. ircSendRPLWHOREPLY(c, ch, client)
  1972. }
  1973. }
  1974. }
  1975. } else {
  1976. for _, client := range users {
  1977. if !onlyOps || 0 != client.mode&ircUserModeOperator {
  1978. ircMatchSendRPLWHOREPLY(c, client, usedMask)
  1979. }
  1980. }
  1981. }
  1982. c.sendReply(RPL_ENDOFWHO, shownMask)
  1983. }
  1984. func ircSendWHOISReply(c, target *client) {
  1985. nick := target.nickname
  1986. c.sendReply(RPL_WHOISUSER, nick,
  1987. target.username, target.hostname, target.realname)
  1988. c.sendReply(RPL_WHOISSERVER, nick, serverName, config["server_info"])
  1989. if 0 != target.mode&ircUserModeOperator {
  1990. c.sendReply(RPL_WHOISOPERATOR, nick)
  1991. }
  1992. c.sendReply(RPL_WHOISIDLE, nick,
  1993. time.Now().Sub(target.lastActive)/time.Second)
  1994. if target.awayMessage != "" {
  1995. c.sendReply(RPL_AWAY, nick, target.awayMessage)
  1996. }
  1997. var chans []string
  1998. for _, ch := range channels {
  1999. _, presentClient := ch.userModes[c]
  2000. modes, presentTarget := ch.userModes[target]
  2001. if presentTarget && (presentClient ||
  2002. 0 == ch.modes&(ircChanModePrivate|ircChanModeSecret)) {
  2003. // TODO: Deduplicate, ircAppendPrefixes just also cuts prefixes.
  2004. var all []byte
  2005. if 0 != modes&ircChanModeOperator {
  2006. all = append(all, '@')
  2007. }
  2008. if 0 != modes&ircChanModeVoice {
  2009. all = append(all, '+')
  2010. }
  2011. chans = append(chans, string(all)+ch.name)
  2012. }
  2013. }
  2014. c.sendReplyVector(RPL_WHOISCHANNELS, chans, nick, "")
  2015. c.sendReply(RPL_ENDOFWHOIS, nick)
  2016. }
  2017. func ircHandleWHOIS(msg *message, c *client) {
  2018. if len(msg.params) < 1 {
  2019. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2020. return
  2021. }
  2022. if len(msg.params) > 1 && !ircIsThisMe(msg.params[0]) {
  2023. c.sendReply(ERR_NOSUCHSERVER, msg.params[0])
  2024. return
  2025. }
  2026. masksStr := msg.params[0]
  2027. if len(msg.params) > 1 {
  2028. masksStr = msg.params[1]
  2029. }
  2030. for _, mask := range splitString(masksStr, ",", true /* ignoreEmpty */) {
  2031. if strings.IndexAny(mask, "*?") < 0 {
  2032. if target := users[ircToCanon(mask)]; target == nil {
  2033. c.sendReply(ERR_NOSUCHNICK, mask)
  2034. } else {
  2035. ircSendWHOISReply(c, target)
  2036. }
  2037. } else {
  2038. found := false
  2039. for _, target := range users {
  2040. if ircFnmatch(mask, target.nickname) {
  2041. ircSendWHOISReply(c, target)
  2042. found = true
  2043. }
  2044. }
  2045. if !found {
  2046. c.sendReply(ERR_NOSUCHNICK, mask)
  2047. }
  2048. }
  2049. }
  2050. }
  2051. func ircHandleWHOWAS(msg *message, c *client) {
  2052. if len(msg.params) < 1 {
  2053. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2054. return
  2055. }
  2056. if len(msg.params) > 2 && !ircIsThisMe(msg.params[2]) {
  2057. c.sendReply(ERR_NOSUCHSERVER, msg.params[2])
  2058. return
  2059. }
  2060. // The "count" parameter is ignored, we only store one entry for a nick.
  2061. for _, nick := range splitString(msg.params[0], ",", true) {
  2062. if info := whowas[ircToCanon(nick)]; info == nil {
  2063. c.sendReply(ERR_WASNOSUCHNICK, nick)
  2064. } else {
  2065. c.sendReply(RPL_WHOWASUSER, nick,
  2066. info.username, info.hostname, info.realname)
  2067. c.sendReply(RPL_WHOISSERVER, nick,
  2068. serverName, config["server_info"])
  2069. }
  2070. c.sendReply(RPL_ENDOFWHOWAS, nick)
  2071. }
  2072. }
  2073. func ircSendRPLTOPIC(c *client, ch *channel) {
  2074. if ch.topic == "" {
  2075. c.sendReply(RPL_NOTOPIC, ch.name)
  2076. } else {
  2077. c.sendReply(RPL_TOPIC, ch.name, ch.topic)
  2078. c.sendReply(RPL_TOPICWHOTIME,
  2079. ch.name, ch.topicWho, ch.topicTime.Unix())
  2080. }
  2081. }
  2082. func ircHandleTOPIC(msg *message, c *client) {
  2083. if len(msg.params) < 1 {
  2084. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2085. return
  2086. }
  2087. channelName := msg.params[0]
  2088. ch := channels[ircToCanon(channelName)]
  2089. if ch == nil {
  2090. c.sendReply(ERR_NOSUCHCHANNEL, channelName)
  2091. return
  2092. }
  2093. if len(msg.params) < 2 {
  2094. ircSendRPLTOPIC(c, ch)
  2095. return
  2096. }
  2097. modes, present := ch.userModes[c]
  2098. if !present {
  2099. c.sendReply(ERR_NOTONCHANNEL, channelName)
  2100. return
  2101. }
  2102. if 0 != ch.modes&ircChanModeProtectedTopic &&
  2103. 0 == modes&ircChanModeOperator {
  2104. c.sendReply(ERR_CHANOPRIVSNEEDED, channelName)
  2105. return
  2106. }
  2107. ch.topic = msg.params[1]
  2108. ch.topicWho = fmt.Sprintf("%s@%s@%s", c.nickname, c.username, c.hostname)
  2109. ch.topicTime = time.Now()
  2110. message := fmt.Sprintf(":%s!%s@%s TOPIC %s :%s",
  2111. c.nickname, c.username, c.hostname, channelName, ch.topic)
  2112. ircChannelMulticast(ch, message, nil)
  2113. }
  2114. func ircTryPart(c *client, channelName string, reason string) {
  2115. if reason == "" {
  2116. reason = c.nickname
  2117. }
  2118. ch := channels[ircToCanon(channelName)]
  2119. if ch == nil {
  2120. c.sendReply(ERR_NOSUCHCHANNEL, channelName)
  2121. return
  2122. }
  2123. if _, present := ch.userModes[c]; !present {
  2124. c.sendReply(ERR_NOTONCHANNEL, channelName)
  2125. return
  2126. }
  2127. message := fmt.Sprintf(":%s@%s@%s PART %s :%s",
  2128. c.nickname, c.username, c.hostname, channelName, reason)
  2129. if 0 == ch.modes&ircChanModeQuiet {
  2130. ircChannelMulticast(ch, message, nil)
  2131. } else {
  2132. c.send(message)
  2133. }
  2134. delete(ch.userModes, c)
  2135. ircChannelDestroyIfEmpty(ch)
  2136. }
  2137. func ircPartAllChannels(c *client) {
  2138. for _, ch := range channels {
  2139. if _, present := ch.userModes[c]; present {
  2140. ircTryPart(c, ch.name, "")
  2141. }
  2142. }
  2143. }
  2144. func ircHandlePART(msg *message, c *client) {
  2145. if len(msg.params) < 1 {
  2146. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2147. return
  2148. }
  2149. reason := ""
  2150. if len(msg.params) > 1 {
  2151. reason = msg.params[1]
  2152. }
  2153. for _, channelName := range splitString(msg.params[0], ",", true) {
  2154. ircTryPart(c, channelName, reason)
  2155. }
  2156. }
  2157. func ircTryKick(c *client, channelName, nick, reason string) {
  2158. ch := channels[ircToCanon(channelName)]
  2159. if ch == nil {
  2160. c.sendReply(ERR_NOSUCHCHANNEL, channelName)
  2161. return
  2162. }
  2163. if modes, present := ch.userModes[c]; !present {
  2164. c.sendReply(ERR_NOTONCHANNEL, channelName)
  2165. return
  2166. } else if 0 == modes&ircChanModeOperator {
  2167. c.sendReply(ERR_CHANOPRIVSNEEDED, channelName)
  2168. return
  2169. }
  2170. client := users[ircToCanon(nick)]
  2171. if _, present := ch.userModes[client]; client == nil || !present {
  2172. c.sendReply(ERR_USERNOTINCHANNEL, nick, channelName)
  2173. return
  2174. }
  2175. message := fmt.Sprintf(":%s@%s@%s KICK %s %s :%s",
  2176. c.nickname, c.username, c.hostname, channelName, nick, reason)
  2177. if 0 == ch.modes&ircChanModeQuiet {
  2178. ircChannelMulticast(ch, message, nil)
  2179. } else {
  2180. c.send(message)
  2181. }
  2182. delete(ch.userModes, client)
  2183. ircChannelDestroyIfEmpty(ch)
  2184. }
  2185. func ircHandleKICK(msg *message, c *client) {
  2186. if len(msg.params) < 2 {
  2187. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2188. return
  2189. }
  2190. reason := c.nickname
  2191. if len(msg.params) > 2 {
  2192. reason = msg.params[2]
  2193. }
  2194. targetChannels := splitString(msg.params[0], ",", true)
  2195. targetUsers := splitString(msg.params[1], ",", true)
  2196. if len(channels) == 1 {
  2197. for i := 0; i < len(targetUsers); i++ {
  2198. ircTryKick(c, targetChannels[0], targetUsers[i], reason)
  2199. }
  2200. } else {
  2201. for i := 0; i < len(channels) && i < len(targetUsers); i++ {
  2202. ircTryKick(c, targetChannels[i], targetUsers[i], reason)
  2203. }
  2204. }
  2205. }
  2206. func ircSendInviteNotifications(ch *channel, c, target *client) {
  2207. for client := range ch.userModes {
  2208. if client != target && 0 != client.capsEnabled&ircCapInviteNotify {
  2209. client.sendf(":%s!%s@%s INVITE %s %s",
  2210. c.nickname, c.username, c.hostname, target.nickname, ch.name)
  2211. }
  2212. }
  2213. }
  2214. func ircHandleINVITE(msg *message, c *client) {
  2215. if len(msg.params) < 2 {
  2216. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2217. return
  2218. }
  2219. target, channelName := msg.params[0], msg.params[1]
  2220. client := users[ircToCanon(target)]
  2221. if client == nil {
  2222. c.sendReply(ERR_NOSUCHNICK, target)
  2223. return
  2224. }
  2225. if ch := channels[ircToCanon(channelName)]; ch != nil {
  2226. invitingModes, invitingPresent := ch.userModes[c]
  2227. if !invitingPresent {
  2228. c.sendReply(ERR_NOTONCHANNEL, channelName)
  2229. return
  2230. }
  2231. if _, present := ch.userModes[client]; present {
  2232. c.sendReply(ERR_USERONCHANNEL, target, channelName)
  2233. return
  2234. }
  2235. if 0 != invitingModes&ircChanModeOperator {
  2236. client.invites[ircToCanon(channelName)] = true
  2237. } else if 0 != ch.modes&ircChanModeInviteOnly {
  2238. c.sendReply(ERR_CHANOPRIVSNEEDED, channelName)
  2239. return
  2240. }
  2241. // It's not specified when and how we should send out invite-notify.
  2242. if 0 != ch.modes&ircChanModeInviteOnly {
  2243. ircSendInviteNotifications(ch, c, client)
  2244. }
  2245. }
  2246. client.sendf(":%s!%s@%s INVITE %s %s",
  2247. c.nickname, c.username, c.hostname, client.nickname, channelName)
  2248. if client.awayMessage != "" {
  2249. c.sendReply(RPL_AWAY, client.nickname, client.awayMessage)
  2250. }
  2251. c.sendReply(RPL_INVITING, client.nickname, channelName)
  2252. }
  2253. func ircTryJoin(c *client, channelName, key string) {
  2254. ch := channels[ircToCanon(channelName)]
  2255. var userMode uint
  2256. if ch == nil {
  2257. if !ircIsValidChannelName(channelName) {
  2258. c.sendReply(ERR_BADCHANMASK, channelName)
  2259. return
  2260. }
  2261. ch = ircChannelCreate(channelName)
  2262. userMode = ircChanModeOperator
  2263. } else if _, present := ch.userModes[c]; present {
  2264. return
  2265. }
  2266. _, invitedByChanop := c.invites[ircToCanon(channelName)]
  2267. if 0 != ch.modes&ircChanModeInviteOnly && c.inMaskList(ch.inviteList) &&
  2268. !invitedByChanop {
  2269. c.sendReply(ERR_INVITEONLYCHAN, channelName)
  2270. return
  2271. }
  2272. if ch.key != "" && (key == "" || key != ch.key) {
  2273. c.sendReply(ERR_BADCHANNELKEY, channelName)
  2274. return
  2275. }
  2276. if ch.userLimit != -1 && len(ch.userModes) >= ch.userLimit {
  2277. c.sendReply(ERR_CHANNELISFULL, channelName)
  2278. return
  2279. }
  2280. if c.inMaskList(ch.banList) && !c.inMaskList(ch.exceptionList) &&
  2281. !invitedByChanop {
  2282. c.sendReply(ERR_BANNEDFROMCHAN, channelName)
  2283. return
  2284. }
  2285. // Destroy any invitation as there's no other way to get rid of it.
  2286. delete(c.invites, ircToCanon(channelName))
  2287. ch.userModes[c] = userMode
  2288. message := fmt.Sprintf(":%s!%s@%s JOIN %s",
  2289. c.nickname, c.username, c.hostname, channelName)
  2290. if 0 == ch.modes&ircChanModeQuiet {
  2291. ircChannelMulticast(ch, message, nil)
  2292. } else {
  2293. c.send(message)
  2294. }
  2295. ircSendRPLTOPIC(c, ch)
  2296. ircSendRPLNAMREPLY(c, ch, nil)
  2297. c.sendReply(RPL_ENDOFNAMES, ch.name)
  2298. }
  2299. func ircHandleJOIN(msg *message, c *client) {
  2300. if len(msg.params) < 1 {
  2301. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2302. return
  2303. }
  2304. if msg.params[0] == "0" {
  2305. ircPartAllChannels(c)
  2306. return
  2307. }
  2308. targetChannels := splitString(msg.params[0], ",", true)
  2309. var keys []string
  2310. if len(msg.params) > 1 {
  2311. keys = splitString(msg.params[1], ",", true)
  2312. }
  2313. for i, name := range targetChannels {
  2314. key := ""
  2315. if i < len(keys) {
  2316. key = keys[i]
  2317. }
  2318. ircTryJoin(c, name, key)
  2319. }
  2320. }
  2321. func ircHandleSUMMON(msg *message, c *client) {
  2322. c.sendReply(ERR_SUMMONDISABLED)
  2323. }
  2324. func ircHandleUSERS(msg *message, c *client) {
  2325. c.sendReply(ERR_USERSDISABLED)
  2326. }
  2327. func ircHandleAWAY(msg *message, c *client) {
  2328. if len(msg.params) < 1 {
  2329. c.awayMessage = ""
  2330. c.sendReply(RPL_UNAWAY)
  2331. } else {
  2332. c.awayMessage = msg.params[0]
  2333. c.sendReply(RPL_NOWAWAY)
  2334. }
  2335. }
  2336. func ircHandleISON(msg *message, c *client) {
  2337. if len(msg.params) < 1 {
  2338. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2339. return
  2340. }
  2341. var on []string
  2342. for _, nick := range msg.params {
  2343. if client := users[ircToCanon(nick)]; client != nil {
  2344. on = append(on, nick)
  2345. }
  2346. }
  2347. c.sendReply(RPL_ISON, strings.Join(on, " "))
  2348. }
  2349. func ircHandleADMIN(msg *message, c *client) {
  2350. if len(msg.params) > 0 && !ircIsThisMe(msg.params[0]) {
  2351. c.sendReply(ERR_NOSUCHSERVER, msg.params[0])
  2352. return
  2353. }
  2354. c.sendReply(ERR_NOADMININFO, serverName)
  2355. }
  2356. func ircHandleStatsLinks(c *client, msg *message) {
  2357. // There is only an "l" query in RFC 2812 but we cannot link,
  2358. // so instead we provide the "L" query giving information for all users.
  2359. filter := ""
  2360. if len(msg.params) > 1 {
  2361. filter = msg.params[1]
  2362. }
  2363. for _, client := range users {
  2364. if filter != "" && !ircEqual(client.nickname, filter) {
  2365. continue
  2366. }
  2367. c.sendReply(RPL_STATSLINKINFO,
  2368. client.address, // linkname
  2369. len(client.sendQ), // sendq
  2370. client.nSentMessages, client.sentBytes/1024,
  2371. client.nReceivedMessages, client.receivedBytes/1024,
  2372. time.Now().Sub(client.opened)/time.Second)
  2373. }
  2374. }
  2375. func ircHandleStatsCommands(c *client) {
  2376. for name, handler := range ircHandlers {
  2377. if handler.nReceived > 0 {
  2378. c.sendReply(RPL_STATSCOMMANDS, name,
  2379. handler.nReceived, handler.bytesReceived, 0)
  2380. }
  2381. }
  2382. }
  2383. // We need to do it this way because of an initialization loop concerning
  2384. // ircHandlers. Workaround proposed by rsc in go #1817.
  2385. var ircHandleStatsCommandsIndirect func(c *client)
  2386. func init() {
  2387. ircHandleStatsCommandsIndirect = ircHandleStatsCommands
  2388. }
  2389. func ircHandleStatsUptime(c *client) {
  2390. uptime := time.Now().Sub(started) / time.Second
  2391. days := uptime / 60 / 60 / 24
  2392. hours := (uptime % (60 * 60 * 24)) / 60 / 60
  2393. mins := (uptime % (60 * 60)) / 60
  2394. secs := uptime % 60
  2395. c.sendReply(RPL_STATSUPTIME, days, hours, mins, secs)
  2396. }
  2397. func ircHandleSTATS(msg *message, c *client) {
  2398. var query byte
  2399. if len(msg.params) > 0 && len(msg.params[0]) > 0 {
  2400. query = msg.params[0][0]
  2401. }
  2402. if len(msg.params) > 1 && !ircIsThisMe(msg.params[1]) {
  2403. c.sendReply(ERR_NOSUCHSERVER, msg.params[0])
  2404. return
  2405. }
  2406. if 0 == c.mode&ircUserModeOperator {
  2407. c.sendReply(ERR_NOPRIVILEGES)
  2408. return
  2409. }
  2410. switch query {
  2411. case 'L':
  2412. ircHandleStatsLinks(c, msg)
  2413. case 'm':
  2414. ircHandleStatsCommandsIndirect(c)
  2415. case 'u':
  2416. ircHandleStatsUptime(c)
  2417. }
  2418. c.sendReply(RPL_ENDOFSTATS, query)
  2419. }
  2420. func ircHandleLINKS(msg *message, c *client) {
  2421. if len(msg.params) > 1 && !ircIsThisMe(msg.params[0]) {
  2422. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2423. return
  2424. }
  2425. mask := "*"
  2426. if len(msg.params) > 0 {
  2427. if len(msg.params) > 1 {
  2428. mask = msg.params[1]
  2429. } else {
  2430. mask = msg.params[0]
  2431. }
  2432. }
  2433. if ircFnmatch(mask, serverName) {
  2434. c.sendReply(RPL_LINKS, mask, serverName,
  2435. 0 /* hop count */, config["server_info"])
  2436. }
  2437. c.sendReply(RPL_ENDOFLINKS, mask)
  2438. }
  2439. func ircHandleKILL(msg *message, c *client) {
  2440. if len(msg.params) < 2 {
  2441. c.sendReply(ERR_NEEDMOREPARAMS, msg.command)
  2442. return
  2443. }
  2444. if 0 == c.mode&ircUserModeOperator {
  2445. c.sendReply(ERR_NOPRIVILEGES)
  2446. return
  2447. }
  2448. target := users[ircToCanon(msg.params[0])]
  2449. if target == nil {
  2450. c.sendReply(ERR_NOSUCHNICK, msg.params[0])
  2451. return
  2452. }
  2453. c.sendf(":%s!%s@%s KILL %s :%s",
  2454. c.nickname, c.username, c.hostname, target.nickname, msg.params[1])
  2455. target.closeLink(fmt.Sprintf("Killed by %s: %s", c.nickname, msg.params[1]))
  2456. }
  2457. func ircHandleDIE(msg *message, c *client) {
  2458. if 0 == c.mode&ircUserModeOperator {
  2459. c.sendReply(ERR_NOPRIVILEGES)
  2460. } else if !quitting {
  2461. initiateQuit()
  2462. }
  2463. }
  2464. // -----------------------------------------------------------------------------
  2465. // TODO: Add an index for ERR_NOSUCHSERVER validation?
  2466. // TODO: Add a minimal parameter count?
  2467. // TODO: Add a field for oper-only commands? Use flags?
  2468. var ircHandlers = map[string]*ircCommand{
  2469. "CAP": {false, ircHandleCAP, 0, 0},
  2470. "PASS": {false, ircHandlePASS, 0, 0},
  2471. "NICK": {false, ircHandleNICK, 0, 0},
  2472. "USER": {false, ircHandleUSER, 0, 0},
  2473. "USERHOST": {true, ircHandleUSERHOST, 0, 0},
  2474. "LUSERS": {true, ircHandleLUSERS, 0, 0},
  2475. "MOTD": {true, ircHandleMOTD, 0, 0},
  2476. "PING": {true, ircHandlePING, 0, 0},
  2477. "PONG": {false, ircHandlePONG, 0, 0},
  2478. "QUIT": {false, ircHandleQUIT, 0, 0},
  2479. "TIME": {true, ircHandleTIME, 0, 0},
  2480. "VERSION": {true, ircHandleVERSION, 0, 0},
  2481. "USERS": {true, ircHandleUSERS, 0, 0},
  2482. "SUMMON": {true, ircHandleSUMMON, 0, 0},
  2483. "AWAY": {true, ircHandleAWAY, 0, 0},
  2484. "ADMIN": {true, ircHandleADMIN, 0, 0},
  2485. "STATS": {true, ircHandleSTATS, 0, 0},
  2486. "LINKS": {true, ircHandleLINKS, 0, 0},
  2487. "MODE": {true, ircHandleMODE, 0, 0},
  2488. "PRIVMSG": {true, ircHandlePRIVMSG, 0, 0},
  2489. "NOTICE": {true, ircHandleNOTICE, 0, 0},
  2490. "JOIN": {true, ircHandleJOIN, 0, 0},
  2491. "PART": {true, ircHandlePART, 0, 0},
  2492. "KICK": {true, ircHandleKICK, 0, 0},
  2493. "INVITE": {true, ircHandleINVITE, 0, 0},
  2494. "TOPIC": {true, ircHandleTOPIC, 0, 0},
  2495. "LIST": {true, ircHandleLIST, 0, 0},
  2496. "NAMES": {true, ircHandleNAMES, 0, 0},
  2497. "WHO": {true, ircHandleWHO, 0, 0},
  2498. "WHOIS": {true, ircHandleWHOIS, 0, 0},
  2499. "WHOWAS": {true, ircHandleWHOWAS, 0, 0},
  2500. "ISON": {true, ircHandleISON, 0, 0},
  2501. "KILL": {true, ircHandleKILL, 0, 0},
  2502. "DIE": {true, ircHandleDIE, 0, 0},
  2503. }
  2504. func ircProcessMessage(c *client, msg *message, raw string) {
  2505. if c.closing {
  2506. return
  2507. }
  2508. c.nReceivedMessages++
  2509. c.receivedBytes += len(raw) + 2
  2510. if !c.antiflood.check() {
  2511. c.closeLink("Excess flood")
  2512. return
  2513. }
  2514. if cmd, ok := ircHandlers[ircToCanon(msg.command)]; !ok {
  2515. c.sendReply(ERR_UNKNOWNCOMMAND, msg.command)
  2516. } else {
  2517. cmd.nReceived++
  2518. cmd.bytesReceived += len(raw) + 2
  2519. if cmd.requiresRegistration && !c.registered {
  2520. c.sendReply(ERR_NOTREGISTERED)
  2521. } else {
  2522. cmd.handler(msg, c)
  2523. }
  2524. }
  2525. }
  2526. // --- Network I/O -------------------------------------------------------------
  2527. // Handle the results from initializing the client's connection.
  2528. func (c *client) onPrepared(host string, isTLS bool) {
  2529. c.printDebug("client resolved to %s, TLS %t", host, isTLS)
  2530. if !isTLS {
  2531. c.conn = c.transport.(connCloseWriter)
  2532. } else if tlsConf != nil {
  2533. c.tls = tls.Server(c.transport, tlsConf)
  2534. c.conn = c.tls
  2535. } else {
  2536. c.printDebug("could not initialize TLS: disabled")
  2537. c.kill("TLS support disabled")
  2538. return
  2539. }
  2540. c.hostname = host
  2541. c.address = net.JoinHostPort(host, c.port)
  2542. // If we tried to send any data before now, we would need to flushSendQ.
  2543. go read(c)
  2544. c.reading = true
  2545. c.setPingTimer()
  2546. }
  2547. // Handle the results from trying to read from the client connection.
  2548. func (c *client) onRead(data []byte, readErr error) {
  2549. if !c.reading {
  2550. // Abusing the flag to emulate CloseRead and skip over data, see below.
  2551. return
  2552. }
  2553. c.recvQ = append(c.recvQ, data...)
  2554. for {
  2555. // XXX: This accepts even simple LF newlines, even though they're not
  2556. // really allowed by the protocol.
  2557. advance, token, _ := bufio.ScanLines(c.recvQ, false /* atEOF */)
  2558. if advance == 0 {
  2559. break
  2560. }
  2561. // XXX: And since it accepts LF, we miscalculate receivedBytes within.
  2562. c.recvQ = c.recvQ[advance:]
  2563. line := string(token)
  2564. c.printDebug("-> %s", line)
  2565. if msg := ircParseMessage(line); msg == nil {
  2566. c.printDebug("error: invalid line")
  2567. } else {
  2568. ircProcessMessage(c, msg, line)
  2569. }
  2570. }
  2571. if readErr != nil {
  2572. c.reading = false
  2573. if readErr != io.EOF {
  2574. c.printDebug("%s", readErr)
  2575. c.kill(readErr.Error())
  2576. } else if c.closing {
  2577. // Disregarding whether a clean shutdown has happened or not.
  2578. c.printDebug("client finished shutdown")
  2579. c.kill("")
  2580. } else {
  2581. c.printDebug("client EOF")
  2582. c.closeLink("")
  2583. }
  2584. } else if len(c.recvQ) > 8192 {
  2585. c.closeLink("recvQ overrun")
  2586. // tls.Conn doesn't have the CloseRead method (and it needs to be able
  2587. // to read from the TCP connection even for writes, so there isn't much
  2588. // sense in expecting the implementation to do anything useful),
  2589. // otherwise we'd use it to block incoming packet data.
  2590. c.reading = false
  2591. }
  2592. }
  2593. // Spawn a goroutine to flush the sendQ if possible and necessary.
  2594. func (c *client) flushSendQ() {
  2595. if !c.writing && c.conn != nil {
  2596. go write(c, c.sendQ)
  2597. c.writing = true
  2598. }
  2599. }
  2600. // Handle the results from trying to write to the client connection.
  2601. func (c *client) onWrite(written int, writeErr error) {
  2602. c.sendQ = c.sendQ[written:]
  2603. c.writing = false
  2604. if writeErr != nil {
  2605. c.printDebug("%s", writeErr)
  2606. c.kill(writeErr.Error())
  2607. } else if len(c.sendQ) > 0 {
  2608. c.flushSendQ()
  2609. } else if c.closing {
  2610. if c.reading {
  2611. c.conn.CloseWrite()
  2612. } else {
  2613. c.kill("")
  2614. }
  2615. }
  2616. }
  2617. // --- Worker goroutines -------------------------------------------------------
  2618. func accept(ln net.Listener) {
  2619. for {
  2620. // Error handling here may be tricky, see go #6163, #24808.
  2621. if conn, err := ln.Accept(); err != nil {
  2622. // See go #4373, they're being dicks. Another solution would be to
  2623. // pass a done channel to this function and close it before closing
  2624. // all the listeners, returning from here if it's readable.
  2625. if strings.Contains(err.Error(),
  2626. "use of closed network connection") {
  2627. return
  2628. }
  2629. if op, ok := err.(net.Error); !ok || !op.Temporary() {
  2630. exitFatal("%s", err)
  2631. } else {
  2632. printError("%s", err)
  2633. }
  2634. } else {
  2635. // TCP_NODELAY is set by default on TCPConns.
  2636. conns <- conn
  2637. }
  2638. }
  2639. }
  2640. func prepare(client *client) {
  2641. conn, host := client.transport, client.hostname
  2642. // The Cgo resolver doesn't pthread_cancel getnameinfo threads, so not
  2643. // bothering with pointless contexts.
  2644. ch := make(chan string, 1)
  2645. go func() {
  2646. defer close(ch)
  2647. if names, err := net.LookupAddr(host); err != nil {
  2648. printError("%s", err)
  2649. } else {
  2650. ch <- names[0]
  2651. }
  2652. }()
  2653. // While we can't cancel it, we still want to set a timeout on it.
  2654. select {
  2655. case <-time.After(5 * time.Second):
  2656. case resolved, ok := <-ch:
  2657. if ok {
  2658. host = resolved
  2659. }
  2660. }
  2661. // Note that in this demo application the autodetection prevents non-TLS
  2662. // clients from receiving any messages until they send something.
  2663. isTLS := false
  2664. if sysconn, err := conn.(syscall.Conn).SyscallConn(); err != nil {
  2665. // This is just for the TLS detection and doesn't need to be fatal.
  2666. printError("%s", err)
  2667. } else {
  2668. isTLS = detectTLS(sysconn)
  2669. }
  2670. prepared <- preparedEvent{client, host, isTLS}
  2671. }
  2672. func read(client *client) {
  2673. // A new buffer is allocated each time we receive some bytes, because of
  2674. // thread-safety. Therefore the buffer shouldn't be too large, or we'd
  2675. // need to copy it each time into a precisely sized new buffer.
  2676. var err error
  2677. for err == nil {
  2678. var (
  2679. buf [512]byte
  2680. n int
  2681. )
  2682. n, err = client.conn.Read(buf[:])
  2683. reads <- readEvent{client, buf[:n], err}
  2684. }
  2685. }
  2686. // Flush sendQ, which is passed by parameter so that there are no data races.
  2687. func write(client *client, data []byte) {
  2688. // We just write as much as we can, the main goroutine does the looping.
  2689. n, err := client.conn.Write(data)
  2690. writes <- writeEvent{client, n, err}
  2691. }
  2692. // --- Event loop --------------------------------------------------------------
  2693. func processOneEvent() {
  2694. select {
  2695. case <-sigs:
  2696. if quitting {
  2697. forceQuit("requested by user")
  2698. } else {
  2699. initiateQuit()
  2700. }
  2701. case <-quitTimer:
  2702. forceQuit("timeout")
  2703. case callback := <-timers:
  2704. callback()
  2705. case conn := <-conns:
  2706. if maxConnections > 0 && len(clients) >= maxConnections {
  2707. printDebug("connection limit reached, refusing connection")
  2708. conn.Close()
  2709. break
  2710. }
  2711. address := conn.RemoteAddr().String()
  2712. host, port, err := net.SplitHostPort(address)
  2713. if err != nil {
  2714. // In effect, we require TCP/UDP, as they have port numbers.
  2715. exitFatal("%s", err)
  2716. }
  2717. c := &client{
  2718. transport: conn,
  2719. address: address,
  2720. hostname: host,
  2721. port: port,
  2722. capVersion: 301,
  2723. opened: time.Now(),
  2724. lastActive: time.Now(),
  2725. // TODO: Make this configurable and more fine-grained.
  2726. antiflood: newFloodDetector(10*time.Second, 20),
  2727. }
  2728. clients[c] = true
  2729. c.printDebug("new client")
  2730. go prepare(c)
  2731. // The TLS autodetection in prepare needs to have a timeout.
  2732. c.setKillTimer()
  2733. case ev := <-prepared:
  2734. if _, ok := clients[ev.client]; ok {
  2735. ev.client.onPrepared(ev.host, ev.isTLS)
  2736. }
  2737. case ev := <-reads:
  2738. if _, ok := clients[ev.client]; ok {
  2739. ev.client.onRead(ev.data, ev.err)
  2740. }
  2741. case ev := <-writes:
  2742. if _, ok := clients[ev.client]; ok {
  2743. ev.client.onWrite(ev.written, ev.err)
  2744. }
  2745. }
  2746. }
  2747. // --- Application setup -------------------------------------------------------
  2748. func ircInitializeTLS() error {
  2749. configCert, configKey := config["tls_cert"], config["tls_key"]
  2750. // Only try to enable SSL support if the user configures it; it is not
  2751. // a failure if no one has requested it.
  2752. if configCert == "" && configKey == "" {
  2753. return nil
  2754. } else if configCert == "" {
  2755. return errors.New("no TLS certificate set")
  2756. } else if configKey == "" {
  2757. return errors.New("no TLS private key set")
  2758. }
  2759. pathCert := resolveFilename(configCert, resolveRelativeConfigFilename)
  2760. if pathCert == "" {
  2761. return fmt.Errorf("cannot find file: %s", configCert)
  2762. }
  2763. pathKey := resolveFilename(configKey, resolveRelativeConfigFilename)
  2764. if pathKey == "" {
  2765. return fmt.Errorf("cannot find file: %s", configKey)
  2766. }
  2767. cert, err := tls.LoadX509KeyPair(pathCert, pathKey)
  2768. if err != nil {
  2769. return err
  2770. }
  2771. tlsConf = &tls.Config{
  2772. Certificates: []tls.Certificate{cert},
  2773. ClientAuth: tls.RequestClientCert,
  2774. SessionTicketsDisabled: true,
  2775. }
  2776. return nil
  2777. }
  2778. func ircInitializeCatalog() error {
  2779. configCatalog := config["catalog"]
  2780. if configCatalog == "" {
  2781. return nil
  2782. }
  2783. path := resolveFilename(configCatalog, resolveRelativeConfigFilename)
  2784. if path == "" {
  2785. return fmt.Errorf("cannot find file: %s", configCatalog)
  2786. }
  2787. f, err := os.Open(path)
  2788. if err != nil {
  2789. return fmt.Errorf("failed reading the MOTD file: %s", err)
  2790. }
  2791. defer f.Close()
  2792. scanner := bufio.NewScanner(f)
  2793. catalog = make(map[int]string)
  2794. for lineNo := 1; scanner.Scan(); lineNo++ {
  2795. line := strings.TrimLeft(scanner.Text(), " \t")
  2796. if line == "" || strings.HasPrefix(line, "#") {
  2797. continue
  2798. }
  2799. delim := strings.IndexAny(line, " \t")
  2800. if delim < 0 {
  2801. return fmt.Errorf("%s:%d: malformed line", path, lineNo)
  2802. }
  2803. id, err := strconv.ParseUint(line[:delim], 10, 16)
  2804. if err != nil {
  2805. return fmt.Errorf("%s:%d: %s", path, lineNo, err)
  2806. }
  2807. catalog[int(id)] = line[delim+1:]
  2808. }
  2809. return scanner.Err()
  2810. }
  2811. func ircInitializeMOTD() error {
  2812. configMOTD := config["motd"]
  2813. if configMOTD == "" {
  2814. return nil
  2815. }
  2816. path := resolveFilename(configMOTD, resolveRelativeConfigFilename)
  2817. if path == "" {
  2818. return fmt.Errorf("cannot find file: %s", configMOTD)
  2819. }
  2820. f, err := os.Open(path)
  2821. if err != nil {
  2822. return fmt.Errorf("failed reading the MOTD file: %s", err)
  2823. }
  2824. defer f.Close()
  2825. scanner := bufio.NewScanner(f)
  2826. motd = nil
  2827. for scanner.Scan() {
  2828. motd = append(motd, scanner.Text())
  2829. }
  2830. return scanner.Err()
  2831. }
  2832. type configProcessor struct {
  2833. err error // any error that has occurred so far
  2834. }
  2835. func (cp *configProcessor) read(name string, process func(string) string) {
  2836. if cp.err != nil {
  2837. return
  2838. }
  2839. if err := process(config[name]); err != "" {
  2840. cp.err = fmt.Errorf("invalid configuration value for `%s': %s",
  2841. name, err)
  2842. }
  2843. }
  2844. // This function handles values that require validation before their first use,
  2845. // or some kind of a transformation (such as conversion to an integer) needs
  2846. // to be done before they can be used directly.
  2847. func ircParseConfig() error {
  2848. cp := &configProcessor{}
  2849. cp.read("ping_interval", func(value string) string {
  2850. if u, err := strconv.ParseUint(
  2851. config["ping_interval"], 10, 32); err != nil {
  2852. return err.Error()
  2853. } else if u < 1 {
  2854. return "the value is out of range"
  2855. } else {
  2856. pingInterval = time.Second * time.Duration(u)
  2857. }
  2858. return ""
  2859. })
  2860. cp.read("max_connections", func(value string) string {
  2861. if i, err := strconv.ParseInt(
  2862. value, 10, 32); err != nil {
  2863. return err.Error()
  2864. } else if i < 0 {
  2865. return "the value is out of range"
  2866. } else {
  2867. maxConnections = int(i)
  2868. }
  2869. return ""
  2870. })
  2871. cp.read("operators", func(value string) string {
  2872. operators = make(map[string]bool)
  2873. for _, fp := range splitString(value, ",", true) {
  2874. if !ircIsValidFingerprint(fp) {
  2875. return "invalid fingerprint value"
  2876. }
  2877. operators[strings.ToLower(fp)] = true
  2878. }
  2879. return ""
  2880. })
  2881. return cp.err
  2882. }
  2883. func ircInitializeServerName() error {
  2884. if value := config["server_name"]; value != "" {
  2885. if err := ircValidateHostname(value); err != nil {
  2886. return err
  2887. }
  2888. serverName = value
  2889. return nil
  2890. }
  2891. if hostname, err := os.Hostname(); err != nil {
  2892. return err
  2893. } else if err := ircValidateHostname(hostname); err != nil {
  2894. return err
  2895. } else {
  2896. serverName = hostname
  2897. }
  2898. return nil
  2899. }
  2900. func ircSetupListenFDs() error {
  2901. for _, address := range splitString(config["bind"], ",", true) {
  2902. ln, err := net.Listen("tcp", address)
  2903. if err != nil {
  2904. return err
  2905. }
  2906. listeners = append(listeners, ln)
  2907. printStatus("listening on %s", address)
  2908. }
  2909. if len(listeners) == 0 {
  2910. return errors.New("network setup failed: no ports to listen on")
  2911. }
  2912. for _, ln := range listeners {
  2913. go accept(ln)
  2914. }
  2915. return nil
  2916. }
  2917. // --- Main --------------------------------------------------------------------
  2918. func main() {
  2919. flag.BoolVar(&debugMode, "debug", false, "run in verbose debug mode")
  2920. version := flag.Bool("version", false, "show version and exit")
  2921. writeDefaultCfg := flag.Bool("writedefaultcfg", false,
  2922. "write a default configuration file and exit")
  2923. systemd := flag.Bool("systemd", false, "log in systemd format")
  2924. flag.Parse()
  2925. if *version {
  2926. fmt.Printf("%s %s\n", projectName, projectVersion)
  2927. return
  2928. }
  2929. if *writeDefaultCfg {
  2930. callSimpleConfigWriteDefault("", configTable)
  2931. return
  2932. }
  2933. if *systemd {
  2934. logMessage = logMessageSystemd
  2935. }
  2936. if flag.NArg() > 0 {
  2937. flag.Usage()
  2938. os.Exit(2)
  2939. }
  2940. config = make(simpleConfig)
  2941. config.loadDefaults(configTable)
  2942. if err := config.updateFromFile(); err != nil && !os.IsNotExist(err) {
  2943. printError("error loading configuration: %s", err)
  2944. os.Exit(1)
  2945. }
  2946. started = time.Now()
  2947. signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
  2948. for _, fn := range []func() error{
  2949. ircInitializeTLS,
  2950. ircInitializeServerName,
  2951. ircInitializeMOTD,
  2952. ircInitializeCatalog,
  2953. ircParseConfig,
  2954. ircSetupListenFDs,
  2955. } {
  2956. if err := fn(); err != nil {
  2957. exitFatal("%s", err)
  2958. }
  2959. }
  2960. for !quitting || len(clients) > 0 {
  2961. processOneEvent()
  2962. }
  2963. }