source: code/trunk/downstream.go@ 183

Last change on this file since 183 was 183, checked in by contact, 5 years ago

Add downstreamConn.clientName

File size: 31.6 KB
RevLine 
[98]1package soju
[13]2
3import (
[91]4 "crypto/tls"
[112]5 "encoding/base64"
[13]6 "fmt"
7 "io"
8 "net"
[108]9 "strconv"
[39]10 "strings"
[105]11 "sync"
[91]12 "time"
[13]13
[112]14 "github.com/emersion/go-sasl"
[85]15 "golang.org/x/crypto/bcrypt"
[13]16 "gopkg.in/irc.v3"
17)
18
19type ircError struct {
20 Message *irc.Message
21}
22
[85]23func (err ircError) Error() string {
24 return err.Message.String()
25}
26
[13]27func newUnknownCommandError(cmd string) ircError {
28 return ircError{&irc.Message{
29 Command: irc.ERR_UNKNOWNCOMMAND,
30 Params: []string{
31 "*",
32 cmd,
33 "Unknown command",
34 },
35 }}
36}
37
38func newNeedMoreParamsError(cmd string) ircError {
39 return ircError{&irc.Message{
40 Command: irc.ERR_NEEDMOREPARAMS,
41 Params: []string{
42 "*",
43 cmd,
44 "Not enough parameters",
45 },
46 }}
47}
48
[85]49var errAuthFailed = ircError{&irc.Message{
50 Command: irc.ERR_PASSWDMISMATCH,
51 Params: []string{"*", "Invalid username or password"},
52}}
[13]53
[104]54type ringMessage struct {
[69]55 consumer *RingConsumer
56 upstreamConn *upstreamConn
57}
58
[13]59type downstreamConn struct {
[154]60 id uint64
[69]61 net net.Conn
62 irc *irc.Conn
63 srv *Server
64 logger Logger
[102]65 outgoing chan *irc.Message
[104]66 ringMessages chan ringMessage
[69]67 closed chan struct{}
[22]68
[100]69 registered bool
70 user *user
71 nick string
72 username string
73 rawUsername string
[168]74 networkName string
[183]75 clientName string
[100]76 realname string
[141]77 hostname string
[100]78 password string // empty after authentication
79 network *network // can be nil
[105]80
[108]81 negociatingCaps bool
82 capVersion int
83 caps map[string]bool
84
[112]85 saslServer sasl.Server
86
[105]87 lock sync.Mutex
88 ourMessages map[*irc.Message]struct{}
[13]89}
90
[154]91func newDownstreamConn(srv *Server, netConn net.Conn, id uint64) *downstreamConn {
[55]92 dc := &downstreamConn{
[154]93 id: id,
[69]94 net: netConn,
95 irc: irc.NewConn(netConn),
96 srv: srv,
97 logger: &prefixLogger{srv.Logger, fmt.Sprintf("downstream %q: ", netConn.RemoteAddr())},
[102]98 outgoing: make(chan *irc.Message, 64),
[104]99 ringMessages: make(chan ringMessage),
[69]100 closed: make(chan struct{}),
[108]101 caps: make(map[string]bool),
[105]102 ourMessages: make(map[*irc.Message]struct{}),
[22]103 }
[141]104 dc.hostname = netConn.RemoteAddr().String()
105 if host, _, err := net.SplitHostPort(dc.hostname); err == nil {
106 dc.hostname = host
107 }
[26]108
109 go func() {
[56]110 if err := dc.writeMessages(); err != nil {
111 dc.logger.Printf("failed to write message: %v", err)
[26]112 }
[55]113 if err := dc.net.Close(); err != nil {
114 dc.logger.Printf("failed to close connection: %v", err)
[45]115 } else {
[55]116 dc.logger.Printf("connection closed")
[45]117 }
[26]118 }()
119
[130]120 dc.logger.Printf("new connection")
[55]121 return dc
[22]122}
123
[55]124func (dc *downstreamConn) prefix() *irc.Prefix {
[27]125 return &irc.Prefix{
[55]126 Name: dc.nick,
127 User: dc.username,
[141]128 Host: dc.hostname,
[27]129 }
130}
131
[90]132func (dc *downstreamConn) forEachNetwork(f func(*network)) {
133 if dc.network != nil {
134 f(dc.network)
135 } else {
136 dc.user.forEachNetwork(f)
137 }
138}
139
[73]140func (dc *downstreamConn) forEachUpstream(f func(*upstreamConn)) {
141 dc.user.forEachUpstream(func(uc *upstreamConn) {
[77]142 if dc.network != nil && uc.network != dc.network {
[73]143 return
144 }
145 f(uc)
146 })
147}
148
[89]149// upstream returns the upstream connection, if any. If there are zero or if
150// there are multiple upstream connections, it returns nil.
151func (dc *downstreamConn) upstream() *upstreamConn {
152 if dc.network == nil {
153 return nil
154 }
[136]155 return dc.network.upstream()
[89]156}
157
[129]158func (dc *downstreamConn) marshalEntity(uc *upstreamConn, entity string) string {
159 if uc.isChannel(entity) {
160 return dc.marshalChannel(uc, entity)
[119]161 }
[129]162 return dc.marshalNick(uc, entity)
[119]163}
164
165func (dc *downstreamConn) marshalChannel(uc *upstreamConn, name string) string {
[130]166 if dc.network != nil {
[119]167 return name
168 }
169 return name + "/" + uc.network.GetName()
170}
171
[127]172func (dc *downstreamConn) unmarshalEntity(name string) (*upstreamConn, string, error) {
[89]173 if uc := dc.upstream(); uc != nil {
174 return uc, name, nil
175 }
176
[127]177 var conn *upstreamConn
[119]178 if i := strings.LastIndexByte(name, '/'); i >= 0 {
[127]179 network := name[i+1:]
[119]180 name = name[:i]
181
182 dc.forEachUpstream(func(uc *upstreamConn) {
183 if network != uc.network.GetName() {
184 return
185 }
186 conn = uc
187 })
188 }
189
[127]190 if conn == nil {
[73]191 return nil, "", ircError{&irc.Message{
192 Command: irc.ERR_NOSUCHCHANNEL,
193 Params: []string{name, "No such channel"},
194 }}
[69]195 }
[127]196 return conn, name, nil
[69]197}
198
199func (dc *downstreamConn) marshalNick(uc *upstreamConn, nick string) string {
200 if nick == uc.nick {
201 return dc.nick
202 }
[130]203 if dc.network != nil {
[119]204 return nick
205 }
206 return nick + "/" + uc.network.GetName()
[69]207}
208
209func (dc *downstreamConn) marshalUserPrefix(uc *upstreamConn, prefix *irc.Prefix) *irc.Prefix {
210 if prefix.Name == uc.nick {
211 return dc.prefix()
212 }
[130]213 if dc.network != nil {
[119]214 return prefix
215 }
216 return &irc.Prefix{
217 Name: prefix.Name + "/" + uc.network.GetName(),
218 User: prefix.User,
219 Host: prefix.Host,
220 }
[69]221}
222
[57]223func (dc *downstreamConn) isClosed() bool {
224 select {
225 case <-dc.closed:
226 return true
227 default:
228 return false
229 }
230}
231
[165]232func (dc *downstreamConn) readMessages(ch chan<- event) error {
[22]233 for {
[55]234 msg, err := dc.irc.ReadMessage()
[22]235 if err == io.EOF {
236 break
237 } else if err != nil {
238 return fmt.Errorf("failed to read IRC command: %v", err)
239 }
240
[64]241 if dc.srv.Debug {
242 dc.logger.Printf("received: %v", msg)
243 }
244
[165]245 ch <- eventDownstreamMessage{msg, dc}
[22]246 }
247
[45]248 return nil
[22]249}
250
[56]251func (dc *downstreamConn) writeMessages() error {
[57]252 for {
253 var err error
254 var closed bool
255 select {
[102]256 case msg := <-dc.outgoing:
[64]257 if dc.srv.Debug {
258 dc.logger.Printf("sent: %v", msg)
259 }
[57]260 err = dc.irc.WriteMessage(msg)
[104]261 case ringMessage := <-dc.ringMessages:
262 consumer, uc := ringMessage.consumer, ringMessage.upstreamConn
[57]263 for {
264 msg := consumer.Peek()
265 if msg == nil {
266 break
267 }
[105]268
269 dc.lock.Lock()
270 _, ours := dc.ourMessages[msg]
271 delete(dc.ourMessages, msg)
272 dc.lock.Unlock()
273 if ours {
274 // The message comes from our connection, don't echo it
275 // back
[113]276 consumer.Consume()
[105]277 continue
278 }
279
[69]280 msg = msg.Copy()
281 switch msg.Command {
282 case "PRIVMSG":
[119]283 msg.Prefix = dc.marshalUserPrefix(uc, msg.Prefix)
284 msg.Params[0] = dc.marshalEntity(uc, msg.Params[0])
[69]285 default:
286 panic("expected to consume a PRIVMSG message")
287 }
[64]288 if dc.srv.Debug {
289 dc.logger.Printf("sent: %v", msg)
290 }
[57]291 err = dc.irc.WriteMessage(msg)
292 if err != nil {
293 break
294 }
295 consumer.Consume()
296 }
297 case <-dc.closed:
298 closed = true
299 }
300 if err != nil {
[56]301 return err
302 }
[57]303 if closed {
304 break
305 }
[56]306 }
307 return nil
308}
309
[180]310// Close closes the connection. It is safe to call from any goroutine.
[55]311func (dc *downstreamConn) Close() error {
[57]312 if dc.isClosed() {
[26]313 return fmt.Errorf("downstream connection already closed")
314 }
[57]315 close(dc.closed)
[45]316 return nil
[13]317}
318
[180]319// SendMessage queues a new outgoing message. It is safe to call from any
320// goroutine.
[55]321func (dc *downstreamConn) SendMessage(msg *irc.Message) {
[102]322 dc.outgoing <- msg
[54]323}
324
[55]325func (dc *downstreamConn) handleMessage(msg *irc.Message) error {
[13]326 switch msg.Command {
[28]327 case "QUIT":
[55]328 return dc.Close()
[13]329 default:
[55]330 if dc.registered {
331 return dc.handleMessageRegistered(msg)
[13]332 } else {
[55]333 return dc.handleMessageUnregistered(msg)
[13]334 }
335 }
336}
337
[55]338func (dc *downstreamConn) handleMessageUnregistered(msg *irc.Message) error {
[13]339 switch msg.Command {
340 case "NICK":
[117]341 var nick string
342 if err := parseMessageParams(msg, &nick); err != nil {
[43]343 return err
[13]344 }
[117]345 if nick == serviceNick {
346 return ircError{&irc.Message{
347 Command: irc.ERR_NICKNAMEINUSE,
348 Params: []string{dc.nick, nick, "Nickname reserved for bouncer service"},
349 }}
350 }
351 dc.nick = nick
[13]352 case "USER":
[117]353 if err := parseMessageParams(msg, &dc.rawUsername, nil, nil, &dc.realname); err != nil {
[43]354 return err
[13]355 }
[85]356 case "PASS":
357 if err := parseMessageParams(msg, &dc.password); err != nil {
358 return err
359 }
[108]360 case "CAP":
361 var subCmd string
362 if err := parseMessageParams(msg, &subCmd); err != nil {
363 return err
364 }
365 if err := dc.handleCapCommand(subCmd, msg.Params[1:]); err != nil {
366 return err
367 }
[112]368 case "AUTHENTICATE":
369 if !dc.caps["sasl"] {
370 return ircError{&irc.Message{
[125]371 Command: irc.ERR_SASLFAIL,
[112]372 Params: []string{"*", "AUTHENTICATE requires the \"sasl\" capability to be enabled"},
373 }}
374 }
375 if len(msg.Params) == 0 {
376 return ircError{&irc.Message{
[125]377 Command: irc.ERR_SASLFAIL,
[112]378 Params: []string{"*", "Missing AUTHENTICATE argument"},
379 }}
380 }
381 if dc.nick == "" {
382 return ircError{&irc.Message{
[125]383 Command: irc.ERR_SASLFAIL,
[112]384 Params: []string{"*", "Expected NICK command before AUTHENTICATE"},
385 }}
386 }
387
388 var resp []byte
389 if dc.saslServer == nil {
390 mech := strings.ToUpper(msg.Params[0])
391 switch mech {
392 case "PLAIN":
393 dc.saslServer = sasl.NewPlainServer(sasl.PlainAuthenticator(func(identity, username, password string) error {
394 return dc.authenticate(username, password)
395 }))
396 default:
397 return ircError{&irc.Message{
[125]398 Command: irc.ERR_SASLFAIL,
[112]399 Params: []string{"*", fmt.Sprintf("Unsupported SASL mechanism %q", mech)},
400 }}
401 }
402 } else if msg.Params[0] == "*" {
403 dc.saslServer = nil
404 return ircError{&irc.Message{
[125]405 Command: irc.ERR_SASLABORTED,
[112]406 Params: []string{"*", "SASL authentication aborted"},
407 }}
408 } else if msg.Params[0] == "+" {
409 resp = nil
410 } else {
411 // TODO: multi-line messages
412 var err error
413 resp, err = base64.StdEncoding.DecodeString(msg.Params[0])
414 if err != nil {
415 dc.saslServer = nil
416 return ircError{&irc.Message{
[125]417 Command: irc.ERR_SASLFAIL,
[112]418 Params: []string{"*", "Invalid base64-encoded response"},
419 }}
420 }
421 }
422
423 challenge, done, err := dc.saslServer.Next(resp)
424 if err != nil {
425 dc.saslServer = nil
426 if ircErr, ok := err.(ircError); ok && ircErr.Message.Command == irc.ERR_PASSWDMISMATCH {
427 return ircError{&irc.Message{
[125]428 Command: irc.ERR_SASLFAIL,
[112]429 Params: []string{"*", ircErr.Message.Params[1]},
430 }}
431 }
432 dc.SendMessage(&irc.Message{
433 Prefix: dc.srv.prefix(),
[125]434 Command: irc.ERR_SASLFAIL,
[112]435 Params: []string{"*", "SASL error"},
436 })
437 return fmt.Errorf("SASL authentication failed: %v", err)
438 } else if done {
439 dc.saslServer = nil
440 dc.SendMessage(&irc.Message{
441 Prefix: dc.srv.prefix(),
[125]442 Command: irc.RPL_LOGGEDIN,
[112]443 Params: []string{dc.nick, dc.nick, dc.user.Username, "You are now logged in"},
444 })
445 dc.SendMessage(&irc.Message{
446 Prefix: dc.srv.prefix(),
[125]447 Command: irc.RPL_SASLSUCCESS,
[112]448 Params: []string{dc.nick, "SASL authentication successful"},
449 })
450 } else {
451 challengeStr := "+"
[135]452 if len(challenge) > 0 {
[112]453 challengeStr = base64.StdEncoding.EncodeToString(challenge)
454 }
455
456 // TODO: multi-line messages
457 dc.SendMessage(&irc.Message{
458 Prefix: dc.srv.prefix(),
459 Command: "AUTHENTICATE",
460 Params: []string{challengeStr},
461 })
462 }
[13]463 default:
[55]464 dc.logger.Printf("unhandled message: %v", msg)
[13]465 return newUnknownCommandError(msg.Command)
466 }
[108]467 if dc.rawUsername != "" && dc.nick != "" && !dc.negociatingCaps {
[55]468 return dc.register()
[13]469 }
470 return nil
471}
472
[108]473func (dc *downstreamConn) handleCapCommand(cmd string, args []string) error {
[111]474 cmd = strings.ToUpper(cmd)
475
[108]476 replyTo := dc.nick
477 if !dc.registered {
478 replyTo = "*"
479 }
480
481 switch cmd {
482 case "LS":
483 if len(args) > 0 {
484 var err error
485 if dc.capVersion, err = strconv.Atoi(args[0]); err != nil {
486 return err
487 }
488 }
489
490 var caps []string
[112]491 if dc.capVersion >= 302 {
[108]492 caps = append(caps, "sasl=PLAIN")
493 } else {
494 caps = append(caps, "sasl")
[112]495 }
[108]496
497 // TODO: multi-line replies
498 dc.SendMessage(&irc.Message{
499 Prefix: dc.srv.prefix(),
500 Command: "CAP",
501 Params: []string{replyTo, "LS", strings.Join(caps, " ")},
502 })
503
504 if !dc.registered {
505 dc.negociatingCaps = true
506 }
507 case "LIST":
508 var caps []string
509 for name := range dc.caps {
510 caps = append(caps, name)
511 }
512
513 // TODO: multi-line replies
514 dc.SendMessage(&irc.Message{
515 Prefix: dc.srv.prefix(),
516 Command: "CAP",
517 Params: []string{replyTo, "LIST", strings.Join(caps, " ")},
518 })
519 case "REQ":
520 if len(args) == 0 {
521 return ircError{&irc.Message{
522 Command: err_invalidcapcmd,
523 Params: []string{replyTo, cmd, "Missing argument in CAP REQ command"},
524 }}
525 }
526
527 caps := strings.Fields(args[0])
528 ack := true
529 for _, name := range caps {
530 name = strings.ToLower(name)
531 enable := !strings.HasPrefix(name, "-")
532 if !enable {
533 name = strings.TrimPrefix(name, "-")
534 }
535
536 enabled := dc.caps[name]
537 if enable == enabled {
538 continue
539 }
540
541 switch name {
[112]542 case "sasl":
543 dc.caps[name] = enable
[108]544 default:
545 ack = false
546 }
547 }
548
549 reply := "NAK"
550 if ack {
551 reply = "ACK"
552 }
553 dc.SendMessage(&irc.Message{
554 Prefix: dc.srv.prefix(),
555 Command: "CAP",
556 Params: []string{replyTo, reply, args[0]},
557 })
558 case "END":
559 dc.negociatingCaps = false
560 default:
561 return ircError{&irc.Message{
562 Command: err_invalidcapcmd,
563 Params: []string{replyTo, cmd, "Unknown CAP command"},
564 }}
565 }
566 return nil
567}
568
[91]569func sanityCheckServer(addr string) error {
570 dialer := net.Dialer{Timeout: 30 * time.Second}
571 conn, err := tls.DialWithDialer(&dialer, "tcp", addr, nil)
572 if err != nil {
573 return err
574 }
575 return conn.Close()
576}
577
[183]578func unmarshalUsername(rawUsername string) (username, client, network string) {
[112]579 username = rawUsername
[183]580
581 i := strings.IndexAny(username, "/@")
582 j := strings.LastIndexAny(username, "/@")
583 if i >= 0 {
584 username = rawUsername[:i]
[73]585 }
[183]586 if j >= 0 {
587 network = rawUsername[j+1:]
[73]588 }
[183]589 if i >= 0 && j >= 0 && i < j {
590 client = rawUsername[i+1 : j]
591 }
592
593 return username, client, network
[112]594}
[73]595
[168]596func (dc *downstreamConn) authenticate(username, password string) error {
[183]597 username, clientName, networkName := unmarshalUsername(username)
[168]598
[173]599 u, err := dc.srv.db.GetUser(username)
600 if err != nil {
601 dc.logger.Printf("failed authentication for %q: %v", username, err)
[168]602 return errAuthFailed
603 }
604
[173]605 err = bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
[168]606 if err != nil {
607 dc.logger.Printf("failed authentication for %q: %v", username, err)
608 return errAuthFailed
609 }
610
[173]611 dc.user = dc.srv.getUser(username)
612 if dc.user == nil {
613 dc.logger.Printf("failed authentication for %q: user not active", username)
614 return errAuthFailed
615 }
[183]616 dc.clientName = clientName
[168]617 dc.networkName = networkName
618 return nil
619}
620
621func (dc *downstreamConn) register() error {
622 if dc.registered {
623 return fmt.Errorf("tried to register twice")
624 }
625
626 password := dc.password
627 dc.password = ""
628 if dc.user == nil {
629 if err := dc.authenticate(dc.rawUsername, password); err != nil {
630 return err
631 }
632 }
633
[183]634 if dc.clientName == "" && dc.networkName == "" {
635 _, dc.clientName, dc.networkName = unmarshalUsername(dc.rawUsername)
[168]636 }
637
638 dc.registered = true
639 dc.username = dc.user.Username
640 dc.logger.Printf("registration complete for user %q", dc.username)
641 return nil
642}
643
644func (dc *downstreamConn) loadNetwork() error {
645 if dc.networkName == "" {
[112]646 return nil
647 }
[85]648
[168]649 network := dc.user.getNetwork(dc.networkName)
[112]650 if network == nil {
[168]651 addr := dc.networkName
[112]652 if !strings.ContainsRune(addr, ':') {
653 addr = addr + ":6697"
654 }
655
656 dc.logger.Printf("trying to connect to new network %q", addr)
657 if err := sanityCheckServer(addr); err != nil {
658 dc.logger.Printf("failed to connect to %q: %v", addr, err)
659 return ircError{&irc.Message{
660 Command: irc.ERR_PASSWDMISMATCH,
[168]661 Params: []string{"*", fmt.Sprintf("Failed to connect to %q", dc.networkName)},
[112]662 }}
663 }
664
[168]665 dc.logger.Printf("auto-saving network %q", dc.networkName)
[112]666 var err error
[120]667 network, err = dc.user.createNetwork(&Network{
[168]668 Addr: dc.networkName,
[120]669 Nick: dc.nick,
670 })
[112]671 if err != nil {
672 return err
673 }
674 }
675
676 dc.network = network
677 return nil
678}
679
[168]680func (dc *downstreamConn) welcome() error {
681 if dc.user == nil || !dc.registered {
682 panic("tried to welcome an unregistered connection")
[37]683 }
684
[168]685 // TODO: doing this might take some time. We should do it in dc.register
686 // instead, but we'll potentially be adding a new network and this must be
687 // done in the user goroutine.
688 if err := dc.loadNetwork(); err != nil {
689 return err
[85]690 }
691
[166]692 firstDownstream := len(dc.user.downstreamConns) == 0
[40]693
[55]694 dc.SendMessage(&irc.Message{
695 Prefix: dc.srv.prefix(),
[13]696 Command: irc.RPL_WELCOME,
[98]697 Params: []string{dc.nick, "Welcome to soju, " + dc.nick},
[54]698 })
[55]699 dc.SendMessage(&irc.Message{
700 Prefix: dc.srv.prefix(),
[13]701 Command: irc.RPL_YOURHOST,
[55]702 Params: []string{dc.nick, "Your host is " + dc.srv.Hostname},
[54]703 })
[55]704 dc.SendMessage(&irc.Message{
705 Prefix: dc.srv.prefix(),
[13]706 Command: irc.RPL_CREATED,
[55]707 Params: []string{dc.nick, "Who cares when the server was created?"},
[54]708 })
[55]709 dc.SendMessage(&irc.Message{
710 Prefix: dc.srv.prefix(),
[13]711 Command: irc.RPL_MYINFO,
[98]712 Params: []string{dc.nick, dc.srv.Hostname, "soju", "aiwroO", "OovaimnqpsrtklbeI"},
[54]713 })
[93]714 // TODO: RPL_ISUPPORT
[55]715 dc.SendMessage(&irc.Message{
716 Prefix: dc.srv.prefix(),
[13]717 Command: irc.ERR_NOMOTD,
[55]718 Params: []string{dc.nick, "No MOTD"},
[54]719 })
[13]720
[73]721 dc.forEachUpstream(func(uc *upstreamConn) {
[30]722 for _, ch := range uc.channels {
723 if ch.complete {
[132]724 dc.SendMessage(&irc.Message{
725 Prefix: dc.prefix(),
726 Command: "JOIN",
727 Params: []string{dc.marshalChannel(ch.conn, ch.Name)},
728 })
729
[55]730 forwardChannel(dc, ch)
[30]731 }
732 }
[143]733 })
[50]734
[143]735 dc.forEachNetwork(func(net *network) {
[144]736 // TODO: need to take dc.network into account when deciding whether or
737 // not to load history
738 dc.runNetwork(net, firstDownstream)
739 })
[57]740
[144]741 return nil
742}
743
744// runNetwork starts listening for messages coming from the network's ring
745// buffer.
746//
747// It panics if the network is not suitable for the downstream connection.
748func (dc *downstreamConn) runNetwork(net *network, loadHistory bool) {
749 if dc.network != nil && net != dc.network {
750 panic("network not suitable for downstream connection")
751 }
752
753 historyName := dc.rawUsername
754
755 var seqPtr *uint64
756 if loadHistory {
757 net.lock.Lock()
758 seq, ok := net.history[historyName]
759 net.lock.Unlock()
760 if ok {
761 seqPtr = &seq
[50]762 }
[144]763 }
[57]764
[144]765 consumer, ch := net.ring.NewConsumer(seqPtr)
766 go func() {
767 for {
768 var closed bool
769 select {
770 case <-ch:
771 uc := net.upstream()
772 if uc == nil {
773 dc.logger.Printf("ignoring messages for upstream %q: upstream is disconnected", net.Addr)
[57]774 break
775 }
[144]776 dc.ringMessages <- ringMessage{consumer, uc}
777 case <-dc.closed:
778 closed = true
[57]779 }
[144]780 if closed {
781 break
782 }
783 }
[57]784
[144]785 seq := consumer.Close()
[57]786
[167]787 net.lock.Lock()
788 net.history[historyName] = seq
789 net.lock.Unlock()
[144]790 }()
[13]791}
792
[103]793func (dc *downstreamConn) runUntilRegistered() error {
794 for !dc.registered {
795 msg, err := dc.irc.ReadMessage()
[106]796 if err != nil {
[103]797 return fmt.Errorf("failed to read IRC command: %v", err)
798 }
799
[110]800 if dc.srv.Debug {
801 dc.logger.Printf("received: %v", msg)
802 }
803
[103]804 err = dc.handleMessage(msg)
805 if ircErr, ok := err.(ircError); ok {
806 ircErr.Message.Prefix = dc.srv.prefix()
807 dc.SendMessage(ircErr.Message)
808 } else if err != nil {
809 return fmt.Errorf("failed to handle IRC command %q: %v", msg, err)
810 }
811 }
812
813 return nil
814}
815
[55]816func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
[13]817 switch msg.Command {
[111]818 case "CAP":
819 var subCmd string
820 if err := parseMessageParams(msg, &subCmd); err != nil {
821 return err
822 }
823 if err := dc.handleCapCommand(subCmd, msg.Params[1:]); err != nil {
824 return err
825 }
[107]826 case "PING":
827 dc.SendMessage(&irc.Message{
828 Prefix: dc.srv.prefix(),
829 Command: "PONG",
830 Params: msg.Params,
831 })
832 return nil
[42]833 case "USER":
[13]834 return ircError{&irc.Message{
835 Command: irc.ERR_ALREADYREGISTERED,
[55]836 Params: []string{dc.nick, "You may not reregister"},
[13]837 }}
[42]838 case "NICK":
[90]839 var nick string
840 if err := parseMessageParams(msg, &nick); err != nil {
841 return err
842 }
843
844 var err error
845 dc.forEachNetwork(func(n *network) {
846 if err != nil {
847 return
848 }
849 n.Nick = nick
850 err = dc.srv.db.StoreNetwork(dc.user.Username, &n.Network)
851 })
852 if err != nil {
853 return err
854 }
855
[73]856 dc.forEachUpstream(func(uc *upstreamConn) {
[60]857 uc.SendMessage(msg)
[42]858 })
[146]859 case "JOIN":
860 var namesStr string
861 if err := parseMessageParams(msg, &namesStr); err != nil {
[48]862 return err
863 }
864
[146]865 var keys []string
866 if len(msg.Params) > 1 {
867 keys = strings.Split(msg.Params[1], ",")
868 }
869
870 for i, name := range strings.Split(namesStr, ",") {
[145]871 uc, upstreamName, err := dc.unmarshalEntity(name)
872 if err != nil {
[158]873 return err
[145]874 }
[48]875
[146]876 var key string
877 if len(keys) > i {
878 key = keys[i]
879 }
880
881 params := []string{upstreamName}
882 if key != "" {
883 params = append(params, key)
884 }
[145]885 uc.SendMessage(&irc.Message{
[146]886 Command: "JOIN",
887 Params: params,
[145]888 })
[89]889
[146]890 err = dc.srv.db.StoreChannel(uc.network.ID, &Channel{
891 Name: upstreamName,
892 Key: key,
893 })
894 if err != nil {
895 dc.logger.Printf("failed to create channel %q in DB: %v", upstreamName, err)
[89]896 }
897 }
[146]898 case "PART":
899 var namesStr string
900 if err := parseMessageParams(msg, &namesStr); err != nil {
901 return err
902 }
903
904 var reason string
905 if len(msg.Params) > 1 {
906 reason = msg.Params[1]
907 }
908
909 for _, name := range strings.Split(namesStr, ",") {
910 uc, upstreamName, err := dc.unmarshalEntity(name)
911 if err != nil {
[158]912 return err
[146]913 }
914
915 params := []string{upstreamName}
916 if reason != "" {
917 params = append(params, reason)
918 }
919 uc.SendMessage(&irc.Message{
920 Command: "PART",
921 Params: params,
922 })
923
924 if err := dc.srv.db.DeleteChannel(uc.network.ID, upstreamName); err != nil {
925 dc.logger.Printf("failed to delete channel %q in DB: %v", upstreamName, err)
926 }
927 }
[159]928 case "KICK":
929 var channelStr, userStr string
930 if err := parseMessageParams(msg, &channelStr, &userStr); err != nil {
931 return err
932 }
933
934 channels := strings.Split(channelStr, ",")
935 users := strings.Split(userStr, ",")
936
937 var reason string
938 if len(msg.Params) > 2 {
939 reason = msg.Params[2]
940 }
941
942 if len(channels) != 1 && len(channels) != len(users) {
943 return ircError{&irc.Message{
944 Command: irc.ERR_BADCHANMASK,
945 Params: []string{dc.nick, channelStr, "Bad channel mask"},
946 }}
947 }
948
949 for i, user := range users {
950 var channel string
951 if len(channels) == 1 {
952 channel = channels[0]
953 } else {
954 channel = channels[i]
955 }
956
957 ucChannel, upstreamChannel, err := dc.unmarshalEntity(channel)
958 if err != nil {
959 return err
960 }
961
962 ucUser, upstreamUser, err := dc.unmarshalEntity(user)
963 if err != nil {
964 return err
965 }
966
967 if ucChannel != ucUser {
968 return ircError{&irc.Message{
969 Command: irc.ERR_USERNOTINCHANNEL,
970 Params: []string{dc.nick, user, channel, "They aren't on that channel"},
971 }}
972 }
973 uc := ucChannel
974
975 params := []string{upstreamChannel, upstreamUser}
976 if reason != "" {
977 params = append(params, reason)
978 }
979 uc.SendMessage(&irc.Message{
980 Command: "KICK",
981 Params: params,
982 })
983 }
[69]984 case "MODE":
[46]985 var name string
986 if err := parseMessageParams(msg, &name); err != nil {
987 return err
988 }
989
990 var modeStr string
991 if len(msg.Params) > 1 {
992 modeStr = msg.Params[1]
993 }
994
[139]995 if name == dc.nick {
[46]996 if modeStr != "" {
[73]997 dc.forEachUpstream(func(uc *upstreamConn) {
[69]998 uc.SendMessage(&irc.Message{
999 Command: "MODE",
1000 Params: []string{uc.nick, modeStr},
1001 })
[46]1002 })
1003 } else {
[55]1004 dc.SendMessage(&irc.Message{
1005 Prefix: dc.srv.prefix(),
[46]1006 Command: irc.RPL_UMODEIS,
[129]1007 Params: []string{dc.nick, ""}, // TODO
[54]1008 })
[46]1009 }
[139]1010 return nil
[46]1011 }
[139]1012
1013 uc, upstreamName, err := dc.unmarshalEntity(name)
1014 if err != nil {
1015 return err
1016 }
1017
1018 if !uc.isChannel(upstreamName) {
1019 return ircError{&irc.Message{
1020 Command: irc.ERR_USERSDONTMATCH,
1021 Params: []string{dc.nick, "Cannot change mode for other users"},
1022 }}
1023 }
1024
1025 if modeStr != "" {
1026 params := []string{upstreamName, modeStr}
1027 params = append(params, msg.Params[2:]...)
1028 uc.SendMessage(&irc.Message{
1029 Command: "MODE",
1030 Params: params,
1031 })
1032 } else {
1033 ch, ok := uc.channels[upstreamName]
1034 if !ok {
1035 return ircError{&irc.Message{
1036 Command: irc.ERR_NOSUCHCHANNEL,
1037 Params: []string{dc.nick, name, "No such channel"},
1038 }}
1039 }
1040
1041 if ch.modes == nil {
1042 // we haven't received the initial RPL_CHANNELMODEIS yet
1043 // ignore the request, we will broadcast the modes later when we receive RPL_CHANNELMODEIS
1044 return nil
1045 }
1046
1047 modeStr, modeParams := ch.modes.Format()
1048 params := []string{dc.nick, name, modeStr}
1049 params = append(params, modeParams...)
1050
1051 dc.SendMessage(&irc.Message{
1052 Prefix: dc.srv.prefix(),
1053 Command: irc.RPL_CHANNELMODEIS,
1054 Params: params,
1055 })
[162]1056 if ch.creationTime != "" {
1057 dc.SendMessage(&irc.Message{
1058 Prefix: dc.srv.prefix(),
1059 Command: rpl_creationtime,
1060 Params: []string{dc.nick, name, ch.creationTime},
1061 })
1062 }
[139]1063 }
[160]1064 case "TOPIC":
1065 var channel string
1066 if err := parseMessageParams(msg, &channel); err != nil {
1067 return err
1068 }
1069
1070 uc, upstreamChannel, err := dc.unmarshalEntity(channel)
1071 if err != nil {
1072 return err
1073 }
1074
1075 if len(msg.Params) > 1 { // setting topic
1076 topic := msg.Params[1]
1077 uc.SendMessage(&irc.Message{
1078 Command: "TOPIC",
1079 Params: []string{upstreamChannel, topic},
1080 })
1081 } else { // getting topic
1082 ch, ok := uc.channels[upstreamChannel]
1083 if !ok {
1084 return ircError{&irc.Message{
1085 Command: irc.ERR_NOSUCHCHANNEL,
1086 Params: []string{dc.nick, upstreamChannel, "No such channel"},
1087 }}
1088 }
1089 sendTopic(dc, ch)
1090 }
[177]1091 case "LIST":
1092 // TODO: support ELIST when supported by all upstreams
1093
1094 pl := pendingLIST{
1095 downstreamID: dc.id,
1096 pendingCommands: make(map[int64]*irc.Message),
1097 }
1098 var upstreamChannels map[int64][]string
1099 if len(msg.Params) > 0 {
1100 upstreamChannels = make(map[int64][]string)
1101 channels := strings.Split(msg.Params[0], ",")
1102 for _, channel := range channels {
1103 uc, upstreamChannel, err := dc.unmarshalEntity(channel)
1104 if err != nil {
1105 return err
1106 }
1107 upstreamChannels[uc.network.ID] = append(upstreamChannels[uc.network.ID], upstreamChannel)
1108 }
1109 }
1110
1111 dc.user.pendingLISTs = append(dc.user.pendingLISTs, pl)
1112 dc.forEachUpstream(func(uc *upstreamConn) {
1113 var params []string
1114 if upstreamChannels != nil {
1115 if channels, ok := upstreamChannels[uc.network.ID]; ok {
1116 params = []string{strings.Join(channels, ",")}
1117 } else {
1118 return
1119 }
1120 }
1121 pl.pendingCommands[uc.network.ID] = &irc.Message{
1122 Command: "LIST",
1123 Params: params,
1124 }
[181]1125 uc.trySendLIST(dc.id)
[177]1126 })
[140]1127 case "NAMES":
1128 if len(msg.Params) == 0 {
1129 dc.SendMessage(&irc.Message{
1130 Prefix: dc.srv.prefix(),
1131 Command: irc.RPL_ENDOFNAMES,
1132 Params: []string{dc.nick, "*", "End of /NAMES list"},
1133 })
1134 return nil
1135 }
1136
1137 channels := strings.Split(msg.Params[0], ",")
1138 for _, channel := range channels {
1139 uc, upstreamChannel, err := dc.unmarshalEntity(channel)
1140 if err != nil {
1141 return err
1142 }
1143
1144 ch, ok := uc.channels[upstreamChannel]
1145 if ok {
1146 sendNames(dc, ch)
1147 } else {
1148 // NAMES on a channel we have not joined, ask upstream
[176]1149 uc.SendMessageLabeled(dc.id, &irc.Message{
[140]1150 Command: "NAMES",
1151 Params: []string{upstreamChannel},
1152 })
1153 }
1154 }
[127]1155 case "WHO":
1156 if len(msg.Params) == 0 {
1157 // TODO: support WHO without parameters
1158 dc.SendMessage(&irc.Message{
1159 Prefix: dc.srv.prefix(),
1160 Command: irc.RPL_ENDOFWHO,
[140]1161 Params: []string{dc.nick, "*", "End of /WHO list"},
[127]1162 })
1163 return nil
1164 }
1165
1166 // TODO: support WHO masks
1167 entity := msg.Params[0]
1168
[142]1169 if entity == dc.nick {
1170 // TODO: support AWAY (H/G) in self WHO reply
1171 dc.SendMessage(&irc.Message{
1172 Prefix: dc.srv.prefix(),
1173 Command: irc.RPL_WHOREPLY,
1174 Params: []string{dc.nick, "*", dc.username, dc.hostname, dc.srv.Hostname, dc.nick, "H", "0 " + dc.realname},
1175 })
1176 dc.SendMessage(&irc.Message{
1177 Prefix: dc.srv.prefix(),
1178 Command: irc.RPL_ENDOFWHO,
1179 Params: []string{dc.nick, dc.nick, "End of /WHO list"},
1180 })
1181 return nil
1182 }
1183
[127]1184 uc, upstreamName, err := dc.unmarshalEntity(entity)
1185 if err != nil {
1186 return err
1187 }
1188
1189 var params []string
1190 if len(msg.Params) == 2 {
1191 params = []string{upstreamName, msg.Params[1]}
1192 } else {
1193 params = []string{upstreamName}
1194 }
1195
[176]1196 uc.SendMessageLabeled(dc.id, &irc.Message{
[127]1197 Command: "WHO",
1198 Params: params,
1199 })
[128]1200 case "WHOIS":
1201 if len(msg.Params) == 0 {
1202 return ircError{&irc.Message{
1203 Command: irc.ERR_NONICKNAMEGIVEN,
1204 Params: []string{dc.nick, "No nickname given"},
1205 }}
1206 }
1207
1208 var target, mask string
1209 if len(msg.Params) == 1 {
1210 target = ""
1211 mask = msg.Params[0]
1212 } else {
1213 target = msg.Params[0]
1214 mask = msg.Params[1]
1215 }
1216 // TODO: support multiple WHOIS users
1217 if i := strings.IndexByte(mask, ','); i >= 0 {
1218 mask = mask[:i]
1219 }
1220
[142]1221 if mask == dc.nick {
1222 dc.SendMessage(&irc.Message{
1223 Prefix: dc.srv.prefix(),
1224 Command: irc.RPL_WHOISUSER,
1225 Params: []string{dc.nick, dc.nick, dc.username, dc.hostname, "*", dc.realname},
1226 })
1227 dc.SendMessage(&irc.Message{
1228 Prefix: dc.srv.prefix(),
1229 Command: irc.RPL_WHOISSERVER,
1230 Params: []string{dc.nick, dc.nick, dc.srv.Hostname, "soju"},
1231 })
1232 dc.SendMessage(&irc.Message{
1233 Prefix: dc.srv.prefix(),
1234 Command: irc.RPL_ENDOFWHOIS,
1235 Params: []string{dc.nick, dc.nick, "End of /WHOIS list"},
1236 })
1237 return nil
1238 }
1239
[128]1240 // TODO: support WHOIS masks
1241 uc, upstreamNick, err := dc.unmarshalEntity(mask)
1242 if err != nil {
1243 return err
1244 }
1245
1246 var params []string
1247 if target != "" {
1248 params = []string{target, upstreamNick}
1249 } else {
1250 params = []string{upstreamNick}
1251 }
1252
[176]1253 uc.SendMessageLabeled(dc.id, &irc.Message{
[128]1254 Command: "WHOIS",
1255 Params: params,
1256 })
[58]1257 case "PRIVMSG":
1258 var targetsStr, text string
1259 if err := parseMessageParams(msg, &targetsStr, &text); err != nil {
1260 return err
1261 }
1262
1263 for _, name := range strings.Split(targetsStr, ",") {
[117]1264 if name == serviceNick {
1265 handleServicePRIVMSG(dc, text)
1266 continue
1267 }
1268
[127]1269 uc, upstreamName, err := dc.unmarshalEntity(name)
[58]1270 if err != nil {
1271 return err
1272 }
1273
[95]1274 if upstreamName == "NickServ" {
1275 dc.handleNickServPRIVMSG(uc, text)
1276 }
1277
[69]1278 uc.SendMessage(&irc.Message{
[58]1279 Command: "PRIVMSG",
[69]1280 Params: []string{upstreamName, text},
[60]1281 })
[105]1282
[113]1283 echoMsg := &irc.Message{
1284 Prefix: &irc.Prefix{
1285 Name: uc.nick,
1286 User: uc.username,
1287 },
[114]1288 Command: "PRIVMSG",
[113]1289 Params: []string{upstreamName, text},
1290 }
[105]1291 dc.lock.Lock()
[113]1292 dc.ourMessages[echoMsg] = struct{}{}
[105]1293 dc.lock.Unlock()
1294
[143]1295 uc.network.ring.Produce(echoMsg)
[58]1296 }
[164]1297 case "NOTICE":
1298 var targetsStr, text string
1299 if err := parseMessageParams(msg, &targetsStr, &text); err != nil {
1300 return err
1301 }
1302
1303 for _, name := range strings.Split(targetsStr, ",") {
1304 uc, upstreamName, err := dc.unmarshalEntity(name)
1305 if err != nil {
1306 return err
1307 }
1308
1309 uc.SendMessage(&irc.Message{
1310 Command: "NOTICE",
1311 Params: []string{upstreamName, text},
1312 })
1313 }
[163]1314 case "INVITE":
1315 var user, channel string
1316 if err := parseMessageParams(msg, &user, &channel); err != nil {
1317 return err
1318 }
1319
1320 ucChannel, upstreamChannel, err := dc.unmarshalEntity(channel)
1321 if err != nil {
1322 return err
1323 }
1324
1325 ucUser, upstreamUser, err := dc.unmarshalEntity(user)
1326 if err != nil {
1327 return err
1328 }
1329
1330 if ucChannel != ucUser {
1331 return ircError{&irc.Message{
1332 Command: irc.ERR_USERNOTINCHANNEL,
1333 Params: []string{dc.nick, user, channel, "They aren't on that channel"},
1334 }}
1335 }
1336 uc := ucChannel
1337
[176]1338 uc.SendMessageLabeled(dc.id, &irc.Message{
[163]1339 Command: "INVITE",
1340 Params: []string{upstreamUser, upstreamChannel},
1341 })
[13]1342 default:
[55]1343 dc.logger.Printf("unhandled message: %v", msg)
[13]1344 return newUnknownCommandError(msg.Command)
1345 }
[42]1346 return nil
[13]1347}
[95]1348
1349func (dc *downstreamConn) handleNickServPRIVMSG(uc *upstreamConn, text string) {
1350 username, password, ok := parseNickServCredentials(text, uc.nick)
1351 if !ok {
1352 return
1353 }
1354
1355 dc.logger.Printf("auto-saving NickServ credentials with username %q", username)
1356 n := uc.network
1357 n.SASL.Mechanism = "PLAIN"
1358 n.SASL.Plain.Username = username
1359 n.SASL.Plain.Password = password
1360 if err := dc.srv.db.StoreNetwork(dc.user.Username, &n.Network); err != nil {
1361 dc.logger.Printf("failed to save NickServ credentials: %v", err)
1362 }
1363}
1364
1365func parseNickServCredentials(text, nick string) (username, password string, ok bool) {
1366 fields := strings.Fields(text)
1367 if len(fields) < 2 {
1368 return "", "", false
1369 }
1370 cmd := strings.ToUpper(fields[0])
1371 params := fields[1:]
1372 switch cmd {
1373 case "REGISTER":
1374 username = nick
1375 password = params[0]
1376 case "IDENTIFY":
1377 if len(params) == 1 {
1378 username = nick
[182]1379 password = params[0]
[95]1380 } else {
1381 username = params[0]
[182]1382 password = params[1]
[95]1383 }
[182]1384 case "SET":
1385 if len(params) == 2 && strings.EqualFold(params[0], "PASSWORD") {
1386 username = nick
1387 password = params[1]
1388 }
[95]1389 }
1390 return username, password, true
1391}
Note: See TracBrowser for help on using the repository browser.