|
|
|
@@ -1343,328 +1343,6 @@ static bool shunt_eroute(connection_t *c, struct spd_route *sr,
|
|
|
|
|
, null_proto_info, op, opname) && ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is only called when s is a likely SAID with trailing protocol i.e.
|
|
|
|
|
* it has the form :-
|
|
|
|
|
*
|
|
|
|
|
* %<keyword>:p
|
|
|
|
|
* <ip-proto><spi>@a.b.c.d:p
|
|
|
|
|
*
|
|
|
|
|
* The task here is to remove the ":p" part so that the rest can be read
|
|
|
|
|
* by another routine.
|
|
|
|
|
*/
|
|
|
|
|
static const char *read_proto(const char * s, size_t * len, int * transport_proto)
|
|
|
|
|
{
|
|
|
|
|
const char * p;
|
|
|
|
|
const char * ugh;
|
|
|
|
|
unsigned long proto;
|
|
|
|
|
size_t l;
|
|
|
|
|
|
|
|
|
|
l = *len;
|
|
|
|
|
p = memchr(s, ':', l);
|
|
|
|
|
if (p == 0)
|
|
|
|
|
{
|
|
|
|
|
*transport_proto = 0;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
ugh = ttoul(p+1, l-((p-s)+1), 10, &proto);
|
|
|
|
|
if (ugh != 0)
|
|
|
|
|
{
|
|
|
|
|
return ugh;
|
|
|
|
|
}
|
|
|
|
|
if (proto > 65535)
|
|
|
|
|
{
|
|
|
|
|
return "protocol number is too large, legal range is 0-65535";
|
|
|
|
|
}
|
|
|
|
|
*len = p-s;
|
|
|
|
|
*transport_proto = proto;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* scan /proc/net/ipsec_eroute every once in a while, looking for:
|
|
|
|
|
*
|
|
|
|
|
* - %hold shunts of which Pluto isn't aware. This situation could
|
|
|
|
|
* be caused by lost ACQUIRE messages. When found, they will
|
|
|
|
|
* added to orphan_holds. This in turn will lead to Opportunistic
|
|
|
|
|
* initiation.
|
|
|
|
|
*
|
|
|
|
|
* - other kinds of shunts that haven't been used recently. These will be
|
|
|
|
|
* deleted. They represent OE failures.
|
|
|
|
|
*
|
|
|
|
|
* - recording recent uses of tunnel eroutes so that rekeying decisions
|
|
|
|
|
* can be made for OE connections.
|
|
|
|
|
*
|
|
|
|
|
* Here are some sample lines:
|
|
|
|
|
* 10 10.3.2.1.0/24 -> 0.0.0.0/0 => %trap
|
|
|
|
|
* 259 10.3.2.1.115/32 -> 10.19.75.161/32 => [email protected]
|
|
|
|
|
* 71 10.44.73.97/32 -> 0.0.0.0/0 => %trap
|
|
|
|
|
* 4119 10.44.73.97/32 -> 10.114.121.41/32 => %pass
|
|
|
|
|
* Newer versions of KLIPS start each line with a 32-bit packet count.
|
|
|
|
|
* If available, the count is used to detect whether a %pass shunt is in use.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: execution time is quadratic in the number of eroutes since the
|
|
|
|
|
* searching for each is sequential. If this becomes a problem, faster
|
|
|
|
|
* searches could be implemented (hash or radix tree, for example).
|
|
|
|
|
*/
|
|
|
|
|
void scan_proc_shunts(void)
|
|
|
|
|
{
|
|
|
|
|
static const char procname[] = "/proc/net/ipsec_eroute";
|
|
|
|
|
FILE *f;
|
|
|
|
|
time_t nw = now();
|
|
|
|
|
int lino;
|
|
|
|
|
struct eroute_info *expired = NULL;
|
|
|
|
|
|
|
|
|
|
event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL);
|
|
|
|
|
|
|
|
|
|
DBG(DBG_CONTROL,
|
|
|
|
|
DBG_log("scanning for shunt eroutes")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/* free any leftover entries: they will be refreshed if still current */
|
|
|
|
|
while (orphaned_holds != NULL)
|
|
|
|
|
{
|
|
|
|
|
struct eroute_info *p = orphaned_holds;
|
|
|
|
|
|
|
|
|
|
orphaned_holds = p->next;
|
|
|
|
|
free(orphaned_holds);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* decode the /proc file. Don't do anything strenuous to it
|
|
|
|
|
* (certainly no PF_KEY stuff) to minimize the chance that it
|
|
|
|
|
* might change underfoot.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
f = fopen(procname, "r");
|
|
|
|
|
if (f == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* for each line... */
|
|
|
|
|
for (lino = 1; ; lino++)
|
|
|
|
|
{
|
|
|
|
|
unsigned char buf[1024]; /* should be big enough */
|
|
|
|
|
chunk_t field[10]; /* 10 is loose upper bound */
|
|
|
|
|
chunk_t *ff = NULL; /* fixed fields (excluding optional count) */
|
|
|
|
|
int fi;
|
|
|
|
|
struct eroute_info eri;
|
|
|
|
|
char *cp;
|
|
|
|
|
err_t context = ""
|
|
|
|
|
, ugh = NULL;
|
|
|
|
|
|
|
|
|
|
cp = fgets(buf, sizeof(buf), f);
|
|
|
|
|
if (cp == NULL)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* break out each field
|
|
|
|
|
* Note: if there are too many fields, just stop;
|
|
|
|
|
* it will be diagnosed a little later.
|
|
|
|
|
*/
|
|
|
|
|
for (fi = 0; fi < (int)countof(field); fi++)
|
|
|
|
|
{
|
|
|
|
|
static const char sep[] = " \t\n"; /* field-separating whitespace */
|
|
|
|
|
size_t w;
|
|
|
|
|
|
|
|
|
|
cp += strspn(cp, sep); /* find start of field */
|
|
|
|
|
w = strcspn(cp, sep); /* find width of field */
|
|
|
|
|
field[fi] = chunk_create(cp, w);
|
|
|
|
|
cp += w;
|
|
|
|
|
if (w == 0)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This odd do-hickey is to share error reporting code.
|
|
|
|
|
* A break will get to that common code. The setting
|
|
|
|
|
* of "ugh" and "context" parameterize it.
|
|
|
|
|
*/
|
|
|
|
|
do {
|
|
|
|
|
/* Old entries have no packet count; new ones do.
|
|
|
|
|
* check if things are as they should be.
|
|
|
|
|
*/
|
|
|
|
|
if (fi == 5)
|
|
|
|
|
{
|
|
|
|
|
ff = &field[0]; /* old form, with no count */
|
|
|
|
|
}
|
|
|
|
|
else if (fi == 6)
|
|
|
|
|
{
|
|
|
|
|
ff = &field[1]; /* new form, with count */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ugh = "has wrong number of fields";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ff[1].len != 2
|
|
|
|
|
|| strncmp(ff[1].ptr, "->", 2) != 0
|
|
|
|
|
|| ff[3].len != 2
|
|
|
|
|
|| strncmp(ff[3].ptr, "=>", 2) != 0)
|
|
|
|
|
{
|
|
|
|
|
ugh = "is missing -> or =>";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* actually digest fields of interest */
|
|
|
|
|
|
|
|
|
|
/* packet count */
|
|
|
|
|
|
|
|
|
|
eri.count = 0;
|
|
|
|
|
if (ff != field)
|
|
|
|
|
{
|
|
|
|
|
context = "count field is malformed: ";
|
|
|
|
|
ugh = ttoul(field[0].ptr, field[0].len, 10, &eri.count);
|
|
|
|
|
if (ugh != NULL)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* our client */
|
|
|
|
|
|
|
|
|
|
context = "source subnet field malformed: ";
|
|
|
|
|
ugh = ttosubnet(ff[0].ptr, ff[0].len, AF_INET, &eri.ours);
|
|
|
|
|
if (ugh != NULL)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* his client */
|
|
|
|
|
|
|
|
|
|
context = "destination subnet field malformed: ";
|
|
|
|
|
ugh = ttosubnet(ff[2].ptr, ff[2].len, AF_INET, &eri.his);
|
|
|
|
|
if (ugh != NULL)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* SAID */
|
|
|
|
|
|
|
|
|
|
context = "SA ID field malformed: ";
|
|
|
|
|
ugh = read_proto(ff[4].ptr, &ff[4].len, &eri.transport_proto);
|
|
|
|
|
if (ugh != NULL)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
ugh = ttosa(ff[4].ptr, ff[4].len, &eri.said);
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
|
|
|
|
if (ugh != NULL)
|
|
|
|
|
{
|
|
|
|
|
plog("INTERNAL ERROR: %s line %d %s%s"
|
|
|
|
|
, procname, lino, context, ugh);
|
|
|
|
|
continue; /* ignore rest of line */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now we have decoded eroute, let's consider it.
|
|
|
|
|
* For shunt eroutes:
|
|
|
|
|
*
|
|
|
|
|
* %hold: if not known, add to orphaned_holds list for initiation
|
|
|
|
|
* because ACQUIRE might have been lost.
|
|
|
|
|
*
|
|
|
|
|
* %pass, %drop, %reject: determine if idle; if so, blast it away.
|
|
|
|
|
* Can occur bare (if DNS provided insufficient information)
|
|
|
|
|
* or with a connection (failure context).
|
|
|
|
|
* Could even be installed by ipsec manual.
|
|
|
|
|
*
|
|
|
|
|
* %trap: always welcome.
|
|
|
|
|
*
|
|
|
|
|
* For other eroutes: find state and record count change
|
|
|
|
|
*/
|
|
|
|
|
if (eri.said.proto == SA_INT)
|
|
|
|
|
{
|
|
|
|
|
/* shunt eroute */
|
|
|
|
|
switch (ntohl(eri.said.spi))
|
|
|
|
|
{
|
|
|
|
|
case SPI_HOLD:
|
|
|
|
|
if (bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto) == NULL
|
|
|
|
|
&& shunt_owner(&eri.ours, &eri.his) == NULL)
|
|
|
|
|
{
|
|
|
|
|
int ourport = ntohs(portof(&eri.ours.addr));
|
|
|
|
|
int hisport = ntohs(portof(&eri.his.addr));
|
|
|
|
|
char ourst[SUBNETTOT_BUF];
|
|
|
|
|
char hist[SUBNETTOT_BUF];
|
|
|
|
|
char sat[SATOT_BUF];
|
|
|
|
|
|
|
|
|
|
subnettot(&eri.ours, 0, ourst, sizeof(ourst));
|
|
|
|
|
subnettot(&eri.his, 0, hist, sizeof(hist));
|
|
|
|
|
satot(&eri.said, 0, sat, sizeof(sat));
|
|
|
|
|
|
|
|
|
|
DBG(DBG_CONTROL,
|
|
|
|
|
DBG_log("add orphaned shunt %s:%d -> %s:%d => %s:%d"
|
|
|
|
|
, ourst, ourport, hist, hisport, sat, eri.transport_proto)
|
|
|
|
|
)
|
|
|
|
|
eri.next = orphaned_holds;
|
|
|
|
|
orphaned_holds = clone_thing(eri);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SPI_PASS:
|
|
|
|
|
case SPI_DROP:
|
|
|
|
|
case SPI_REJECT:
|
|
|
|
|
/* nothing sensible to do if we don't have counts */
|
|
|
|
|
if (ff != field)
|
|
|
|
|
{
|
|
|
|
|
struct bare_shunt **bs_pp
|
|
|
|
|
= bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto);
|
|
|
|
|
|
|
|
|
|
if (bs_pp != NULL)
|
|
|
|
|
{
|
|
|
|
|
struct bare_shunt *bs = *bs_pp;
|
|
|
|
|
|
|
|
|
|
if (eri.count != bs->count)
|
|
|
|
|
{
|
|
|
|
|
bs->count = eri.count;
|
|
|
|
|
bs->last_activity = nw;
|
|
|
|
|
}
|
|
|
|
|
else if (nw - bs->last_activity > SHUNT_PATIENCE)
|
|
|
|
|
{
|
|
|
|
|
eri.next = expired;
|
|
|
|
|
expired = clone_thing(eri);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SPI_TRAP:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
bad_case(ntohl(eri.said.spi));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* regular (non-shunt) eroute */
|
|
|
|
|
state_eroute_usage(&eri.ours, &eri.his, eri.count, nw);
|
|
|
|
|
}
|
|
|
|
|
} /* for each line */
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
|
|
/* Now that we've finished processing the /proc file,
|
|
|
|
|
* it is safe to delete the expired %pass shunts.
|
|
|
|
|
*/
|
|
|
|
|
while (expired != NULL)
|
|
|
|
|
{
|
|
|
|
|
struct eroute_info *p = expired;
|
|
|
|
|
ip_address src, dst;
|
|
|
|
|
|
|
|
|
|
networkof(&p->ours, &src);
|
|
|
|
|
networkof(&p->his, &dst);
|
|
|
|
|
(void) replace_bare_shunt(&src, &dst
|
|
|
|
|
, BOTTOM_PRIO /* not used because we are deleting. This value is a filler */
|
|
|
|
|
, SPI_PASS /* not used because we are deleting. This value is a filler */
|
|
|
|
|
, FALSE, p->transport_proto, "delete expired bare shunts");
|
|
|
|
|
expired = p->next;
|
|
|
|
|
free(p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool del_spi(ipsec_spi_t spi, int proto,
|
|
|
|
|
const ip_address *src, const ip_address *dest)
|
|
|
|
|
{
|
|
|
|
@@ -2371,11 +2049,6 @@ void init_kernel(void)
|
|
|
|
|
/* register SA types that we can negotiate */
|
|
|
|
|
can_do_IPcomp = FALSE; /* until we get a response from KLIPS */
|
|
|
|
|
kernel_ops->pfkey_register();
|
|
|
|
|
|
|
|
|
|
if (!kernel_ops->policy_lifetime)
|
|
|
|
|
{
|
|
|
|
|
event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|