When src_ipaddr is set.
Also fix a bug in parsing the src IP address. For now, it's not
IPv6 capable (sorry)
#
# 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.
+ # proxying requests to this home server. When the src_ipaddr
+ # it set, the server will automatically create a proxy
+ # listener for that IP address.
#
# If you specify this field for one home server, you will
# likely need to specify it for ALL home servers.
# * 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.
+ # in the sample "home_server" section. When you specify the
+ # source IP address for packets sent to a home server, the
+ # proxy listeners are automatically created.
# 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(fr_ipaddr_t *ipaddr);
+rad_listen_t *proxy_new_listener(fr_ipaddr_t *ipaddr, int exists);
RADCLIENT *client_listener_find(const rad_listen_t *listener,
const fr_ipaddr_t *ipaddr, int src_port);
#ifdef WITH_STATS
home_server *home_server_ldb(const char *realmname, home_pool_t *pool, REQUEST *request);
home_server *home_server_find(fr_ipaddr_t *ipaddr, int port);
+int home_server_create_listeners(void *head);
#ifdef WITH_COA
home_server *home_server_byname(const char *name);
#endif
* it to the tail of the list of listeners. With
* some care, this can be thread-safe.
*/
- proxy_listener = proxy_new_listener(&packet->src_ipaddr);
+ proxy_listener = proxy_new_listener(&packet->src_ipaddr, FALSE);
if (!proxy_listener) {
RDEBUG2("ERROR: Failed to create a new socket for proxying requests.");
return 0;
VALUE_PAIR *vp;
if (home->state == HOME_STATE_ALIVE) {
- radlog(L_INFO, "Suspicious proxy state... continuing");
return;
}
* Having it here means that late or duplicate proxy
* replies no longer get the home server marked as
* "alive". This might be good for stability, though.
+ *
+ * FIXME: Do we really want to do this whenever we
+ * receive a packet? Setting this here means that we
+ * mark it alive on *any* packet, even if it's lost all
+ * of the *other* packets in the last 10s.
*/
request->home_server->state = HOME_STATE_ALIVE;
/*
* Externally visible function for creating a new proxy LISTENER.
*
- * For now, don't take ipaddr or port.
- *
* Not thread-safe, but all calls to it are protected by the
- * proxy mutex in request_list.c
+ * proxy mutex in event.c
*/
-rad_listen_t *proxy_new_listener(fr_ipaddr_t *ipaddr)
+rad_listen_t *proxy_new_listener(fr_ipaddr_t *ipaddr, int exists)
{
int last_proxy_port, port;
rad_listen_t *this, *tmp, **last;
listen_socket_t *sock, *old;
- this = listen_alloc(RAD_LISTEN_PROXY);
-
/*
* Find an existing proxy socket to copy.
*/
/*
* If we were asked to copy a specific one, do
- * so.
+ * so. If we're just finding one that already
+ * exists, return a pointer to it. Otherwise,
+ * create ANOTHER one with the same IP address.
*/
if ((ipaddr->af != AF_UNSPEC) &&
- (fr_ipaddr_cmp(&sock->ipaddr, ipaddr) != 0)) continue;
+ (fr_ipaddr_cmp(&sock->ipaddr, ipaddr) != 0)) {
+ if (exists) return tmp;
+ continue;
+ }
if (sock->port > last_proxy_port) {
last_proxy_port = sock->port + 1;
last = &(tmp->next);
}
- if (!old) { /* This is a serious error. */
- listen_free(&this);
- return NULL;
- }
+ if (!old) {
+ /*
+ * The socket MUST already exist if we're binding
+ * to an address while proxying.
+ *
+ * If we're initializing the server, it's OK for the
+ * socket to NOT exist.
+ */
+ if (!exists) return NULL;
- sock = this->data;
- memcpy(&sock->ipaddr, &old->ipaddr, sizeof(sock->ipaddr));
+ this = listen_alloc(RAD_LISTEN_PROXY);
+
+ sock = this->data;
+ sock->ipaddr = *ipaddr;
+
+ } else {
+ this = listen_alloc(RAD_LISTEN_PROXY);
+
+ sock = this->data;
+ sock->ipaddr = old->ipaddr;
+ }
/*
* Keep going until we find an unused port.
*/
for (port = last_proxy_port; port < 64000; port++) {
+ int rcode;
+
sock->port = port;
- if (listen_bind(this) == 0) {
- /*
- * Add the new listener to the list of
- * listeners.
- */
- *last = this;
- return this;
+
+ rcode = listen_bind(this);
+ if (rcode < 0) {
+ listen_free(&this);
+ return NULL;
}
+
+ /*
+ * Add the new listener to the list of
+ * listeners.
+ */
+ *last = this;
+ return this;
}
listen_free(&this);
*/
if (!*head) return -1;
+ /*
+ * Create *additional* proxy listeners, based
+ * on their src_ipaddr.
+ */
+ if (home_server_create_listeners(*head) != 0) return -1;
+
+ /*
+ *
+ */
+ while (*last) last = &((*last)->next);
+
if (defined_proxy) goto done;
/*
#ifdef WITH_PROXY
static struct in_addr hs_ip4addr;
+static struct in_addr hs_srcip4addr;
static struct in6_addr hs_ip6addr;
static char *hs_type = NULL;
static char *hs_check = NULL;
offsetof(home_server,secret), NULL, NULL},
{ "src_ipaddr", PW_TYPE_IPADDR,
- offsetof(home_server,src_ipaddr), NULL, NULL },
+ 0, &hs_srcip4addr, NULL },
{ "response_window", PW_TYPE_INTEGER,
offsetof(home_server,response_window), NULL, "30" },
memset(&hs_ip4addr, 0, sizeof(hs_ip4addr));
memset(&hs_ip6addr, 0, sizeof(hs_ip6addr));
+ memset(&hs_srcip4addr, 0, sizeof(hs_srcip4addr));
if (cf_section_parse(cs, home, home_server_config) < 0) {
free(home);
return 0;
free(hs_type);
hs_type = NULL;
+ /*
+ * FIXME: Add support for IPv6 source addresses
+ */
+ if (hs_srcip4addr.s_addr != htonl(INADDR_ANY)) {
+ home->src_ipaddr.af = AF_INET;
+ home->src_ipaddr.ipaddr.ip4addr = hs_srcip4addr;
+ }
+
if (!hs_check || (strcasecmp(hs_check, "none") == 0)) {
home->ping_check = HOME_PING_CHECK_NONE;
}
#endif
+
+#ifdef WITH_PROXY
+static int home_server_create_callback(void *ctx, void *data)
+{
+ rad_listen_t *head = ctx;
+ home_server *home = data;
+ rad_listen_t *this;
+
+ /*
+ * If there WAS a src address defined, ensure that a
+ * proxy listener has been defined.
+ */
+ if (home->src_ipaddr.af != AF_UNSPEC) {
+ this = proxy_new_listener(&home->src_ipaddr, TRUE);
+
+ /*
+ * Failed to create it: Die
+ */
+ if (!this) return 1;
+
+ this->next = head->next;
+ head->next = this;
+ }
+
+ return 0;
+}
+
+/*
+ * Taking a void* here solves some header issues.
+ */
+int home_server_create_listeners(void *ctx)
+{
+ rad_listen_t *head = ctx;
+
+ if (!home_servers_byaddr) return 0;
+
+ rad_assert(head != NULL);
+
+ /*
+ * Add the listeners to the TAIL of the list.
+ */
+ while (head->next) head = head->next;
+
+ if (rbtree_walk(home_servers_byaddr, InOrder,
+ home_server_create_callback, head) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+#endif