From: Fredrik Tolf Date: Sun, 24 Feb 2008 05:39:20 +0000 (+0100) Subject: Made the DC protocol readers a bit more resilient to faulty peers. X-Git-Tag: 1.2~20 X-Git-Url: http://git.dolda2000.com/gitweb/?p=doldaconnect.git;a=commitdiff_plain;h=8cb2d75b84ddff61bd0e56eb1943931194cf8045 Made the DC protocol readers a bit more resilient to faulty peers. --- diff --git a/daemon/fnet-dc.c b/daemon/fnet-dc.c index 87671aa..dc26782 100644 --- a/daemon/fnet-dc.c +++ b/daemon/fnet-dc.c @@ -91,6 +91,7 @@ struct command char *name; void (*handler)(struct socket *sk, void *data, char *cmd, char *args); int stop; + int limit; }; struct qcommand @@ -102,6 +103,7 @@ struct qcommand struct qcmdqueue { struct qcommand *f, *l; + int size; }; struct dchub @@ -393,6 +395,7 @@ static struct qcommand *newqcmd(struct qcmdqueue *queue, char *string) else queue->l->next = new; queue->l = new; + queue->size++; return(new); } @@ -404,6 +407,7 @@ static struct qcommand *ulqcmd(struct qcmdqueue *queue) return(NULL); if((queue->f = qcmd->next) == NULL) queue->l = NULL; + queue->size--; return(qcmd); } @@ -2628,10 +2632,10 @@ static struct command hubcmds[] = {"$OpList", cc(cmd_oplist)}, {"$MyINFO", cc(cmd_myinfo)}, {"$ForceMove", cc(cmd_forcemove)}, - {"$Search", cc(cmd_search)}, - {"$MultiSearch", cc(cmd_search)}, - {"$ConnectToMe", cc(cmd_connecttome)}, - {"$RevConnectToMe", cc(cmd_revconnecttome)}, + {"$Search", cc(cmd_search), .limit = 100}, + {"$MultiSearch", cc(cmd_search), .limit = 50}, + {"$ConnectToMe", cc(cmd_connecttome), .limit = 200}, + {"$RevConnectToMe", cc(cmd_revconnecttome), .limit = 500}, {"$GetNetInfo", cc(cmd_getnetinfo)}, {"$To:", cc(cmd_to)}, {"$SR", cc(cmd_sr)}, @@ -2659,8 +2663,8 @@ static struct command peercmds[] = {"$GetZBlock", cc(cmd_getblock)}, {"$UGetZBlock", cc(cmd_getblock)}, {"$ADCGET", cc(cmd_adcget)}, - {"$ADCSND", cc(cmd_adcsnd), 1}, - {"$Sending", cc(cmd_sending), 1}, + {"$ADCSND", cc(cmd_adcsnd), .stop = 1}, + {"$Sending", cc(cmd_sending), .stop = 1}, {NULL, NULL} }; #undef cc @@ -2977,8 +2981,9 @@ static void udpread(struct socket *sk, void *data) static void hubread(struct socket *sk, struct fnetnode *fn) { struct dchub *hub; + struct command *cmd; char *newbuf; - size_t datalen; + size_t datalen, cnlen; char *p; hub = (struct dchub *)fn->data; @@ -2994,11 +2999,22 @@ static void hubread(struct socket *sk, struct fnetnode *fn) while((datalen > 0) && ((p = memchr(p, '|', datalen)) != NULL)) { *(p++) = 0; - newqcmd(&hub->queue, hub->inbuf); + for(cmd = hubcmds; cmd->handler != NULL; cmd++) + { + cnlen = strlen(cmd->name); + if(!strncmp(hub->inbuf, cmd->name, cnlen) && ((hub->inbuf[cnlen] == ' ') || (hub->inbuf[cnlen] == 0))) + break; + } + if((cmd->limit == 0) || (hub->queue.size < cmd->limit)) + newqcmd(&hub->queue, hub->inbuf); memmove(hub->inbuf, p, hub->inbufdata -= p - hub->inbuf); datalen = hub->inbufdata; p = hub->inbuf; } + if(hub->queue.size > 1000) + sk->ignread = 1; + else + sk->ignread = 0; } static void huberr(struct socket *sk, int err, struct fnetnode *fn) @@ -3224,11 +3240,13 @@ static struct fnet dcnet = static void peerread(struct socket *sk, struct dcpeer *peer) { char *newbuf, *p; - size_t datalen; + size_t datalen, cnlen; struct command *cmd; if((newbuf = sockgetinbuf(sk, &datalen)) == NULL) return; + if(peer->inbufdata > 500000) /* Discard possibly malicious data */ + peer->inbufdata = 0; sizebuf2(peer->inbuf, peer->inbufdata + datalen, 1); memcpy(peer->inbuf + peer->inbufdata, newbuf, datalen); free(newbuf); @@ -3239,17 +3257,24 @@ static void peerread(struct socket *sk, struct dcpeer *peer) while((peer->inbufdata > 0) && (p = memchr(peer->inbuf, '|', peer->inbufdata)) != NULL) { *(p++) = 0; - newqcmd(&peer->queue, peer->inbuf); for(cmd = peercmds; cmd->handler != NULL; cmd++) { - if(!memcmp(peer->inbuf, cmd->name, strlen(cmd->name)) && ((peer->inbuf[strlen(cmd->name)] == ' ') || (peer->inbuf[strlen(cmd->name)] == '|'))) + cnlen = strlen(cmd->name); + if(!strncmp(peer->inbuf, cmd->name, cnlen) && ((peer->inbuf[cnlen] == ' ') || (peer->inbuf[cnlen] == 0))) break; } + if((cmd->limit == 0) || (peer->queue.size < cmd->limit)) + newqcmd(&peer->queue, peer->inbuf); memmove(peer->inbuf, p, peer->inbufdata -= p - peer->inbuf); if(cmd->stop) { peer->state = PEER_STOP; break; + } else { + if(peer->queue.size > 1000) + sk->ignread = 1; + else + sk->ignread = 0; } } } else if(peer->state == PEER_TTHL) {