From 337a61dd7fb9fdf1b56231fb371ffe5c554e0368 Mon Sep 17 00:00:00 2001 From: cathugger Date: Tue, 23 Jan 2018 22:32:14 +0000 Subject: [PATCH] some NNTP improvements --- contrib/backends/srndv2/src/srnd/nntp.go | 118 +++++++++++++---------- 1 file changed, 68 insertions(+), 50 deletions(-) diff --git a/contrib/backends/srndv2/src/srnd/nntp.go b/contrib/backends/srndv2/src/srnd/nntp.go index bf1865a..cbbfdc3 100644 --- a/contrib/backends/srndv2/src/srnd/nntp.go +++ b/contrib/backends/srndv2/src/srnd/nntp.go @@ -382,18 +382,19 @@ func (self *nntpConnection) handleStreaming(daemon *NNTPDaemon, conn *textproto. return } -// check if we want the article given its mime header +// check if we want the article given its auth status and mime header // returns empty string if it's okay otherwise an error message -func (self *nntpConnection) checkMIMEHeader(daemon *NNTPDaemon, h map[string][]string) (reason string, allow bool, err error) { +func (self *nntpConnection) checkMIMEHeader(daemon *NNTPDaemon, hdr textproto.MIMEHeader) (reason string, allow bool, err error) { if !self.authenticated { reason = "not authenticated" return } - hdr := textproto.MIMEHeader(h) reason, allow, err = self.checkMIMEHeaderNoAuth(daemon, hdr) return } +// check if we want the article given its mime header without checking auth status +// returns empty string if it's okay otherwise an error message func (self *nntpConnection) checkMIMEHeaderNoAuth(daemon *NNTPDaemon, hdr textproto.MIMEHeader) (reason string, ban bool, err error) { newsgroup := hdr.Get("Newsgroups") reference := hdr.Get("References") @@ -664,9 +665,9 @@ func (self *nntpConnection) handleLine(daemon *NNTPDaemon, code int, line string } else if cmd == "CHECK" { // handle check command msgid := parts[1] - if self.mode != "STREAM" { - // we can't we are not in streaming mode - conn.PrintfLine("431 %s", msgid) + if !self.authenticated { + // if client cannot TAKETHIS it shouldn't be able to CHECK either + conn.PrintfLine("480 You have not authenticated") return } // have we seen this article? @@ -682,55 +683,73 @@ func (self *nntpConnection) handleLine(daemon *NNTPDaemon, code int, line string } } else if cmd == "TAKETHIS" { // handle takethis command + r := bufio.NewReader(conn.DotReader()) + if !self.authenticated { + // early reject without parsing incase client not allowed to post + // send response first to allow client to stop sending + // XXX what happens if our send queue is full and this blocks? + // other side will probably fill up sending article to us + // async receive processing would help there + // but this situation has low likehood to happen + // operating system/transport buffering will compensate + // so leave it this way + conn.PrintfLine("480 You have not authenticated") + // discard whole article without looking at insides + // it should be dot-terminated either way + _, err = io.Copy(ioutil.Discard, r) + return + } + // client is allowed to post var msg *mail.Message var reason string var ban bool // read the article header - r := bufio.NewReader(conn.DotReader()) msg, err = readMIMEHeader(r) - if err == nil { - hdr := textproto.MIMEHeader(msg.Header) - // check the header - reason, ban, err = self.checkMIMEHeader(daemon, hdr) - if len(reason) > 0 { - // discard, we do not want - code = 439 - log.Println(self.name, "rejected", msgid, reason) - _, err = io.Copy(ioutil.Discard, msg.Body) - if ban { - err = daemon.database.BanArticle(msgid, reason) - } - } else if err == nil { - // check if we don't have the rootpost - reference := hdr.Get("References") - if reference != "" && ValidMessageID(reference) && !daemon.store.HasArticle(reference) && !daemon.database.IsExpired(reference) { - log.Println(self.name, "got reply to", reference, "but we don't have it") - go daemon.askForArticle(reference) - } - err = storeMessage(daemon, hdr, msg.Body) - if err == nil { - code = 239 - reason = "gotten" - } else { - code = 439 - reason = err.Error() - } - } else { - // error? - // discard, we do not want - code = 439 - log.Println(self.name, "rejected", msgid, reason) - _, err = io.Copy(ioutil.Discard, msg.Body) - if ban { - err = daemon.database.BanArticle(msgid, reason) - } - } - } else { + if err != nil { log.Println(self.name, "error reading mime header:", err) - code = 439 - reason = "error reading mime header" + conn.PrintfLine("439 %s error reading mime header", msgid) + // if reading header error'd, msg.Body wont be set + _, err = io.Copy(ioutil.Discard, r) + return + } + hdr := textproto.MIMEHeader(msg.Header) + // check the header + reason, ban, err = self.checkMIMEHeaderNoAuth(daemon, hdr) + if len(reason) > 0 { + // discard, we do not want + log.Println(self.name, "rejected", msgid, reason) + conn.PrintfLine("439 %s %s", code, msgid, reason) + _, err = io.Copy(ioutil.Discard, msg.Body) + if ban { + err = daemon.database.BanArticle(msgid, reason) + } + } else if err == nil { + // looks good to accept + // check if we don't have the rootpost + reference := hdr.Get("References") + if reference != "" && ValidMessageID(reference) && !daemon.store.HasArticle(reference) && !daemon.database.IsExpired(reference) { + log.Println(self.name, "got reply to", reference, "but we don't have it") + go daemon.askForArticle(reference) + } + err = storeMessage(daemon, hdr, msg.Body) + if err == nil { + code = 239 + reason = "gotten" + } else { + code = 439 + reason = err.Error() + } + conn.PrintfLine("%d %s %s", code, msgid, reason) + } else { + // error? + // discard, we do not want + log.Println(self.name, "rejected", msgid, "unexpected error", err) + conn.PrintfLine("439 %s unexpected error", msgid) + _, err = io.Copy(ioutil.Discard, msg.Body) + if ban { + err = daemon.database.BanArticle(msgid, reason) + } } - conn.PrintfLine("%d %s %s", code, msgid, reason) } else if cmd == "ARTICLE" { if !ValidMessageID(msgid) { if len(self.group) > 0 { @@ -759,7 +778,7 @@ func (self *nntpConnection) handleLine(daemon *NNTPDaemon, code int, line string } } else if cmd == "IHAVE" { if !self.authenticated { - conn.PrintfLine("483 You have not authenticated") + conn.PrintfLine("480 You have not authenticated") } else { // handle IHAVE command msgid := parts[1] @@ -1656,7 +1675,6 @@ func (self *nntpConnection) runConnection(daemon *NNTPDaemon, inbound, stream, r conn.PrintfLine("203 Stream it brah") self.mode = "STREAM" log.Println(self.name, "streaming enabled") - go self.startStreaming(daemon, reader, conn) } } }