diff options
-rw-r--r-- | dtls.c | 11 | ||||
-rw-r--r-- | radsecproxy.c | 84 | ||||
-rw-r--r-- | radsecproxy.h | 21 | ||||
-rw-r--r-- | tcp.c | 11 | ||||
-rw-r--r-- | tls.c | 11 | ||||
-rw-r--r-- | udp.c | 45 | ||||
-rw-r--r-- | util.c | 21 | ||||
-rw-r--r-- | util.h | 3 |
8 files changed, 105 insertions, 102 deletions
@@ -213,7 +213,7 @@ void *dtlsserverwr(void *arg) { unsigned long error; struct client *client = (struct client *)arg; struct queue *replyq; - struct reply *reply; + struct request *reply; debug(DBG_DBG, "dtlsserverwr: starting for %s", client->conf->host); replyq = client->replyq; @@ -233,17 +233,16 @@ void *dtlsserverwr(void *arg) { pthread_exit(NULL); } } - reply = (struct reply *)list_shift(replyq->entries); + reply = (struct request *)list_shift(replyq->entries); pthread_mutex_unlock(&replyq->mutex); - cnt = SSL_write(client->ssl, reply->buf, RADLEN(reply->buf)); + cnt = SSL_write(client->ssl, reply->replybuf, RADLEN(reply->replybuf)); if (cnt > 0) debug(DBG_DBG, "dtlsserverwr: sent %d bytes, Radius packet of length %d", - cnt, RADLEN(reply->buf)); + cnt, RADLEN(reply->replybuf)); else while ((error = ERR_get_error())) debug(DBG_ERR, "dtlsserverwr: SSL: %s", ERR_error_string(error, NULL)); - free(reply->buf); - free(reply); + freerq(reply); } } diff --git a/radsecproxy.c b/radsecproxy.c index 9e3cbe4..6e0c2c6 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -279,16 +279,8 @@ int resolvepeer(struct clsrvconf *conf, int ai_flags) { debug(DBG_WARN, "resolvepeer: can't resolve (null) port (null)"); return 0; } - for (res = addrinfo; res; res = res->ai_next) { - switch (res->ai_family) { - case AF_INET: - ((struct sockaddr_in *)res->ai_addr)->sin_port = 0; - break; - case AF_INET6: - ((struct sockaddr_in6 *)res->ai_addr)->sin6_port = 0; - break; - } - } + for (res = addrinfo; res; res = res->ai_next) + port_set(res->ai_addr, 0); } else { if (slash) hints.ai_flags |= AI_NUMERICHOST; @@ -541,7 +533,7 @@ void removequeue(struct queue *q) { return; pthread_mutex_lock(&q->mutex); for (entry = list_first(q->entries); entry; entry = list_next(entry)) - free(((struct reply *)entry)->buf); + freerq((struct request *)entry); list_destroy(q->entries); pthread_cond_destroy(&q->cond); pthread_mutex_unlock(&q->mutex); @@ -940,10 +932,10 @@ void freerq(struct request *rq) { free(rq->origusername); if (rq->buf) free(rq->buf); - if (rq->msg) { + if (rq->replybuf) + free(rq->replybuf); + if (rq->msg) radmsg_free(rq->msg); - rq->msg = NULL; - } free(rq); } @@ -1013,38 +1005,26 @@ void sendrq(struct server *to, struct request *rq) { pthread_mutex_unlock(&to->newrq_mutex); } -void sendreply(struct client *to, struct radmsg *msg, struct sockaddr_storage *tosa, int toudpsock) { - uint8_t *buf; - struct reply *reply; +void sendreply(struct request *rq) { uint8_t first; - - buf = radmsg2buf(msg, (uint8_t *)to->conf->secret); - radmsg_free(msg); - if (!buf) { + struct client *to = rq->from; + + if (!rq->replybuf) + rq->replybuf = radmsg2buf(rq->msg, (uint8_t *)to->conf->secret); + radmsg_free(rq->msg); + rq->msg = NULL; + if (!rq->replybuf) { + freerq(rq); debug(DBG_ERR, "sendreply: radmsg2buf failed"); return; } - reply = malloc(sizeof(struct reply)); - if (!reply) { - free(buf); - debug(DBG_ERR, "sendreply: malloc failed"); - return; - } - memset(reply, 0, sizeof(struct reply)); - reply->buf = buf; - if (tosa) - reply->tosa = *tosa; - reply->toudpsock = toudpsock; - pthread_mutex_lock(&to->replyq->mutex); - first = list_first(to->replyq->entries) == NULL; - if (!list_push(to->replyq->entries, reply)) { + if (!list_push(to->replyq->entries, rq)) { pthread_mutex_unlock(&to->replyq->mutex); - free(reply); - free(buf); + freerq(rq); debug(DBG_ERR, "sendreply: malloc failed"); return; } @@ -1652,8 +1632,10 @@ void respondaccounting(struct request *rq) { msg = radmsg_init(RAD_Accounting_Response, rq->msg->id, rq->msg->auth); if (msg) { + radmsg_free(rq->msg); + rq->msg = msg; debug(DBG_DBG, "respondaccounting: responding to %s", rq->from->conf->host); - sendreply(rq->from, msg, &rq->fromsa, rq->fromudpsock); + sendreply(rq); } else debug(DBG_ERR, "respondaccounting: malloc failed"); } @@ -1663,8 +1645,10 @@ void respondstatusserver(struct request *rq) { msg = radmsg_init(RAD_Access_Accept, rq->msg->id, rq->msg->auth); if (msg) { + radmsg_free(rq->msg); + rq->msg = msg; debug(DBG_DBG, "respondstatusserver: responding to %s", rq->from->conf->host); - sendreply(rq->from, msg, &rq->fromsa, rq->fromudpsock); + sendreply(rq); } else debug(DBG_ERR, "respondstatusserver: malloc failed"); } @@ -1688,8 +1672,10 @@ void respondreject(struct request *rq, char *message) { } } + radmsg_free(rq->msg); + rq->msg = msg; debug(DBG_DBG, "respondreject: responding to %s", rq->from->conf->host); - sendreply(rq->from, msg, &rq->fromsa, rq->fromudpsock); + sendreply(rq); } struct clsrvconf *choosesrvconf(struct list *srvconfs) { @@ -1763,6 +1749,15 @@ int addclientrq(struct request *rq, uint8_t id) { r = rq->from->rqs[id]; if (r) { if (now.tv_sec - r->created.tv_sec < r->from->conf->dupinterval) { +#if 0 + later + if (r->replybuf) { + debug(DBG_INFO, "radsrv: already sent reply to request with id %d from %s, resending", id, r->from->conf->host); + r->refcount++; + sendreply(r); + } else +#endif + debug(DBG_INFO, "radsrv: already got request with id %d from %s, ignoring", id, r->from->conf->host); pthread_mutex_unlock(&rq->from->lock); return 0; } @@ -1813,10 +1808,8 @@ int radsrv(struct request *rq) { goto exit; } - if (!addclientrq(rq, msg->id)) { - debug(DBG_INFO, "radsrv: already got request with id %d from %s, ignoring", msg->id, from->conf->host); + if (!addclientrq(rq, msg->id)) goto exit; - } if (msg->code == RAD_Status_Server) { respondstatusserver(rq); @@ -2026,7 +2019,10 @@ void replyh(struct server *server, unsigned char *buf) { } debug(DBG_INFO, "replyh: passing reply to client %s", from->conf->name); - sendreply(from, msg, &rqout->rq->fromsa, rqout->rq->fromudpsock); + radmsg_free(rqout->rq->msg); + rqout->rq->msg = msg; + rqout->rq->refcount++; + sendreply(rqout->rq); freerqoutdata(rqout); pthread_mutex_unlock(rqout->lock); return; diff --git a/radsecproxy.h b/radsecproxy.h index 5efe80b..a421c5e 100644 --- a/radsecproxy.h +++ b/radsecproxy.h @@ -45,14 +45,14 @@ struct options { struct request { struct timeval created; uint8_t refcount; - uint8_t *buf; + uint8_t *buf, *replybuf; struct radmsg *msg; struct client *from; - struct sockaddr_storage fromsa; /* used by udpservwr */ - int fromudpsock; /* used by udpservwr */ char *origusername; - char origauth[16]; /* used by servwr */ - uint8_t origid; /* used by servwr */ + char origauth[16]; + uint8_t origid; + int udpsock; /* only for UDP */ + uint16_t udpport; /* only for UDP */ }; /* requests that our client will send */ @@ -63,13 +63,6 @@ struct rqout { struct timeval expiry; }; -/* replies that a server will send */ -struct reply { - unsigned char *buf; - struct sockaddr_storage tosa; /* used by udpservwr */ - int toudpsock; /* used by udpservwr */ -}; - struct queue { struct list *entries; pthread_mutex_t mutex; @@ -206,6 +199,10 @@ struct protodefs { sizeof(struct sockaddr_in) : \ sizeof(struct sockaddr_in6)) +#define SOCKADDRP_SIZE(addr) ((addr)->sa_family == AF_INET ? \ + sizeof(struct sockaddr_in) : \ + sizeof(struct sockaddr_in6)) + struct addrinfo *getsrcprotores(uint8_t type); struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_node **cur); struct clsrvconf *find_srvconf(uint8_t type, struct sockaddr *addr, struct list_node **cur); @@ -190,7 +190,7 @@ void *tcpserverwr(void *arg) { int cnt; struct client *client = (struct client *)arg; struct queue *replyq; - struct reply *reply; + struct request *reply; debug(DBG_DBG, "tcpserverwr: starting for %s", client->conf->host); replyq = client->replyq; @@ -209,16 +209,15 @@ void *tcpserverwr(void *arg) { pthread_exit(NULL); } } - reply = (struct reply *)list_shift(replyq->entries); + reply = (struct request *)list_shift(replyq->entries); pthread_mutex_unlock(&replyq->mutex); - cnt = write(client->sock, reply->buf, RADLEN(reply->buf)); + cnt = write(client->sock, reply->replybuf, RADLEN(reply->replybuf)); if (cnt > 0) debug(DBG_DBG, "tcpserverwr: sent %d bytes, Radius packet of length %d", - cnt, RADLEN(reply->buf)); + cnt, RADLEN(reply->replybuf)); else debug(DBG_ERR, "tcpserverwr: write error for %s", client->conf->host); - free(reply->buf); - free(reply); + freerq(reply); } } @@ -241,7 +241,7 @@ void *tlsserverwr(void *arg) { unsigned long error; struct client *client = (struct client *)arg; struct queue *replyq; - struct reply *reply; + struct request *reply; debug(DBG_DBG, "tlsserverwr: starting for %s", client->conf->host); replyq = client->replyq; @@ -261,17 +261,16 @@ void *tlsserverwr(void *arg) { pthread_exit(NULL); } } - reply = (struct reply *)list_shift(replyq->entries); + reply = (struct request *)list_shift(replyq->entries); pthread_mutex_unlock(&replyq->mutex); - cnt = SSL_write(client->ssl, reply->buf, RADLEN(reply->buf)); + cnt = SSL_write(client->ssl, reply->replybuf, RADLEN(reply->replybuf)); if (cnt > 0) debug(DBG_DBG, "tlsserverwr: sent %d bytes, Radius packet of length %d", - cnt, RADLEN(reply->buf)); + cnt, RADLEN(reply->replybuf)); else while ((error = ERR_get_error())) debug(DBG_ERR, "tlsserverwr: SSL: %s", ERR_error_string(error, NULL)); - free(reply->buf); - free(reply); + freerq(reply); } } @@ -38,7 +38,7 @@ static struct queue *server_replyq = NULL; /* exactly one of client and server must be non-NULL */ /* return who we received from in *client or *server */ /* return from in sa if not NULL */ -unsigned char *radudpget(int s, struct client **client, struct server **server, struct sockaddr_storage *sa) { +unsigned char *radudpget(int s, struct client **client, struct server **server, uint16_t *port) { int cnt, len; unsigned char buf[4], *rad = NULL; struct sockaddr_storage from; @@ -128,8 +128,8 @@ unsigned char *radudpget(int s, struct client **client, struct server **server, *server = p->servers; break; } - if (sa) - *sa = from; + if (port) + *port = port_get((struct sockaddr *)&from); return rad; } @@ -138,32 +138,20 @@ int clientradputudp(struct server *server, unsigned char *rad) { struct sockaddr_storage sa; struct sockaddr *sap; struct clsrvconf *conf = server->conf; - in_port_t *port = NULL; + uint16_t port; len = RADLEN(rad); + port = port_get(conf->addrinfo->ai_addr); if (*rad == RAD_Accounting_Request) { sap = (struct sockaddr *)&sa; memcpy(sap, conf->addrinfo->ai_addr, conf->addrinfo->ai_addrlen); + port_set(sap, ++port); } else sap = conf->addrinfo->ai_addr; - - switch (sap->sa_family) { - case AF_INET: - port = &((struct sockaddr_in *)sap)->sin_port; - break; - case AF_INET6: - port = &((struct sockaddr_in6 *)sap)->sin6_port; - break; - default: - return 0; - } - if (*rad == RAD_Accounting_Request) - *port = htons(ntohs(*port) + 1); - if (sendto(server->sock, rad, len, 0, sap, conf->addrinfo->ai_addrlen) >= 0) { - debug(DBG_DBG, "clienradputudp: sent UDP of length %d to %s port %d", len, conf->host, ntohs(*port)); + debug(DBG_DBG, "clienradputudp: sent UDP of length %d to %s port %d", len, conf->host, port); return 1; } @@ -193,8 +181,8 @@ void *udpserverrd(void *arg) { sleep(5); /* malloc failed */ continue; } - rq->buf = radudpget(*sp, &rq->from, NULL, &rq->fromsa); - rq->fromudpsock = *sp; + rq->buf = radudpget(*sp, &rq->from, NULL, &rq->udpport); + rq->udpsock = *sp; radsrv(rq); } free(sp); @@ -202,22 +190,23 @@ void *udpserverrd(void *arg) { void *udpserverwr(void *arg) { struct queue *replyq = (struct queue *)arg; - struct reply *reply; + struct request *reply; + struct sockaddr_storage to; for (;;) { pthread_mutex_lock(&replyq->mutex); - while (!(reply = (struct reply *)list_shift(replyq->entries))) { + while (!(reply = (struct request *)list_shift(replyq->entries))) { debug(DBG_DBG, "udp server writer, waiting for signal"); pthread_cond_wait(&replyq->cond, &replyq->mutex); debug(DBG_DBG, "udp server writer, got signal"); } pthread_mutex_unlock(&replyq->mutex); - if (sendto(reply->toudpsock, reply->buf, RADLEN(reply->buf), 0, - (struct sockaddr *)&reply->tosa, SOCKADDR_SIZE(reply->tosa)) < 0) - debug(DBG_WARN, "sendudp: send failed"); - free(reply->buf); - free(reply); + memcpy(&to, reply->from->addr, SOCKADDRP_SIZE(reply->from->addr)); + port_set((struct sockaddr *)&to, reply->udpport); + if (sendto(reply->udpsock, reply->replybuf, RADLEN(reply->replybuf), 0, (struct sockaddr *)&to, SOCKADDR_SIZE(to)) < 0) + debug(DBG_WARN, "udpserverwr: send failed"); + freerq(reply); } } @@ -72,6 +72,27 @@ void printfchars(char *prefixfmt, char *prefix, char *charfmt, char *chars, int printf("\n"); } +uint16_t port_get(struct sockaddr *sa) { + switch (sa->sa_family) { + case AF_INET: + return ntohs(((struct sockaddr_in *)sa)->sin_port); + case AF_INET6: + return ntohs(((struct sockaddr_in6 *)sa)->sin6_port); + } + return 0; +} + +void port_set(struct sockaddr *sa, uint16_t port) { + switch (sa->sa_family) { + case AF_INET: + ((struct sockaddr_in *)sa)->sin_port = htons(port); + break; + case AF_INET6: + ((struct sockaddr_in6 *)sa)->sin6_port = htons(port); + break; + } +} + int addr_equal(struct sockaddr *a, struct sockaddr *b) { switch (a->sa_family) { case AF_INET: @@ -5,5 +5,8 @@ char *stringcopy(const char *s, int len); char *addr2string(struct sockaddr *addr, socklen_t len); int addr_equal(struct sockaddr *a, struct sockaddr *b); struct sockaddr *addr_copy(struct sockaddr *in); +uint16_t port_get(struct sockaddr *sa); +void port_set(struct sockaddr *sa, uint16_t port); + void printfchars(char *prefixfmt, char *prefix, char *charfmt, char *chars, int len); int connectport(int type, char *host, char *port); |