#
############################################################
+ #
+ # You can optionally specify the source IP address used when
+ # proxying requests to this home server. When setting the
+ # src_ipaddr, you MUST also configure a listener section of
+ # type "proxy", using the same IP address. Failure to do so
+ # means that the server cannot proxy any requests to this
+ # home server.
+ #
+ # If you specify this field for one home server, you will
+ # likely need to specify it for ALL home servers.
+ #
+ # If you don't care about the source IP address, leave this
+ # entry commented.
+ #
+# src_ipaddr = 127.0.0.1
+
# RFC 5080 suggests that all clients SHOULD include it in an
# Access-Request. The configuration item below tells the
# proxying server (i.e. this one) whether or not the home
# Note: "type = proxy" lets you control the source IP used for
# proxying packets, with some limitations:
#
- # * Only ONE proxy listener can be defined.
# * A proxy listener CANNOT be used in a virtual server section.
# * You should probably set "port = 0".
# * Any "clients" configuration will be ignored.
+ #
+ # See also proxy.conf, and the "src_ipaddr" configuration entry
+ # in the sample "home_server" section. It is possible to specify
+ # the source IP address for packets sent to a home server. In
+ # that situation, you MUST have a proxy listener defined with
+ # that IP address.
# IP address on which to listen.
# Allowed values are:
/* listen.c */
void listen_free(rad_listen_t **head);
int listen_init(CONF_SECTION *cs, rad_listen_t **head);
-rad_listen_t *proxy_new_listener(void);
+rad_listen_t *proxy_new_listener(fr_ipaddr_t *ipaddr);
RADCLIENT *client_listener_find(const rad_listen_t *listener,
const fr_ipaddr_t *ipaddr, int src_port);
#ifdef WITH_STATS
#ifdef WITH_STATS
int number;
+ fr_ipaddr_t src_ipaddr; /* preferred source IP address */
+
fr_stats_t stats;
fr_stats_ema_t ema;
int fr_packet_list_id_alloc(fr_packet_list_t *pl,
RADIUS_PACKET *request)
{
- int i, id, start;
+ int i, id, start, fd;
uint32_t free_mask;
fr_packet_dst2id_t my_pd, *pd;
fr_packet_socket_t *ps;
id = start = (int) fr_rand() & 0xff;
while (pd->id[id] == pl->mask) { /* all sockets are using this ID */
+ redo:
id++;
id &= 0xff;
if (id == start) return 0;
free_mask = ~((~pd->id[id]) & pl->mask);
- start = -1;
+ /*
+ * This ID has at least one socket free. Check the sockets
+ * to see if they are satisfactory for the caller.
+ */
+ fd = -1;
for (i = 0; i < MAX_SOCKETS; i++) {
if (pl->sockets[i].sockfd == -1) continue; /* paranoia */
- if ((free_mask & (1 << i)) == 0) {
- start = i;
- break;
- }
+ /*
+ * This ID is allocated.
+ */
+ if ((free_mask & (1 << i)) != 0) continue;
+
+ /*
+ * If the caller cares about the source address,
+ * try to re-use that. This means that the
+ * requested source address is set, AND this
+ * socket wasn't bound to "*", AND the requested
+ * source address is the same as this socket
+ * address.
+ */
+ if ((request->src_ipaddr.af != AF_UNSPEC) &&
+ !pl->sockets[i].inaddr_any &&
+ (fr_ipaddr_cmp(&request->src_ipaddr, &pl->sockets[i].ipaddr) != 0)) continue;
+
+ /*
+ * They asked for a specific address, and this socket
+ * is bound to a wildcard address. Ignore this one, too.
+ */
+ if ((request->src_ipaddr.af != AF_UNSPEC) &&
+ pl->sockets[i].inaddr_any) continue;
+
+ fd = i;
+ break;
}
- if (start < 0) return 0; /* bad error */
+ if (fd < 0) {
+ goto redo; /* keep searching IDs */
+ }
- pd->id[id] |= (1 << start);
- ps = &pl->sockets[start];
+ pd->id[id] |= (1 << fd);
+ ps = &pl->sockets[fd];
ps->num_outgoing++;
pl->num_outgoing++;
* Not thread-safe, but all calls to it are protected by the
* proxy mutex in request_list.c
*/
-rad_listen_t *proxy_new_listener()
+rad_listen_t *proxy_new_listener(fr_ipaddr_t *ipaddr)
{
int last_proxy_port, port;
rad_listen_t *this, *tmp, **last;
/*
* Find an existing proxy socket to copy.
- *
- * FIXME: Make it per-realm, or per-home server!
*/
last_proxy_port = 0;
old = NULL;
last = &mainconfig.listen;
for (tmp = mainconfig.listen; tmp != NULL; tmp = tmp->next) {
- if (tmp->type == RAD_LISTEN_PROXY) {
- sock = tmp->data;
- if (sock->port > last_proxy_port) {
- last_proxy_port = sock->port + 1;
- }
- if (!old) old = sock;
+ /*
+ * Not proxy, ignore it.
+ */
+ if (tmp->type != RAD_LISTEN_PROXY) continue;
+
+ sock = tmp->data;
+
+ /*
+ * If we were asked to copy a specific one, do
+ * so.
+ */
+ if ((ipaddr->af != AF_UNSPEC) &&
+ (fr_ipaddr_cmp(&sock->ipaddr, ipaddr) != 0)) continue;
+
+ if (sock->port > last_proxy_port) {
+ last_proxy_port = sock->port + 1;
}
+ if (!old) old = sock;
last = &(tmp->next);
}
- if (!old) {
+ if (!old) { /* This is a serious error. */
listen_free(&this);
- return NULL; /* This is a serious error. */
+ return NULL;
}
- /*
- * FIXME: find a new IP address to listen on?
- *
- * This could likely be done in the "home server"
- * configuration, to have per-home-server source IP's.
- */
sock = this->data;
memcpy(&sock->ipaddr, &old->ipaddr, sizeof(sock->ipaddr));
* this packet.
*/
retry:
+ radclient->request->src_ipaddr.af = AF_UNSPEC;
rcode = fr_packet_list_id_alloc(pl, radclient->request);
if (rcode < 0) {
int mysockfd;
{ "secret", PW_TYPE_STRING_PTR,
offsetof(home_server,secret), NULL, NULL},
+ { "src_ipaddr", PW_TYPE_IPADDR,
+ offsetof(home_server,src_ipaddr), NULL, NULL },
+
{ "response_window", PW_TYPE_INTEGER,
offsetof(home_server,response_window), NULL, "30" },
{ "max_outstanding", PW_TYPE_INTEGER,
* the 'hints' file.
*/
request->proxy->vps = paircopy(request->packet->vps);
+
+ /*
+ * Set the source IP address for proxying.
+ */
+ request->proxy->src_ipaddr = found->src_ipaddr;
}
/*