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;
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);
}
}
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;
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);
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);
}
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;
}
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");
}
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");
}
}
}
+ 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) {
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;
}
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);
}
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;
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 */
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;
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);
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;
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);
}
}
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;
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);
}
}
/* 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;
*server = p->servers;
break;
}
- if (sa)
- *sa = from;
+ if (port)
+ *port = port_get((struct sockaddr *)&from);
return 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;
}
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);
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);
}
}
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:
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);