Add support for deleting all kernel tunnels/sessions
Unfortunately, tunnels and session can survive us, so we have to drop any tunnel/session left from a previous instance that might have crashed.
This commit is contained in:
parent
1f4d79ce85
commit
b2bc6da827
1 changed files with 192 additions and 4 deletions
196
l2tpns.c
196
l2tpns.c
|
|
@ -471,6 +471,132 @@ void random_data(uint8_t *buf, int len)
|
|||
buf[n++] = (rand() >> 4) & 0xff;
|
||||
}
|
||||
|
||||
//
|
||||
// Clear all existing kernel items of a given type
|
||||
static int delete_kernel_items(const char *name, int cmd, int id1, int id2, void (*delete_one)(uint32_t id1, uint32_t id2))
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr nh;
|
||||
struct genlmsghdr glh;
|
||||
char data[8192];
|
||||
} req;
|
||||
int seqnum;
|
||||
|
||||
if (genl_l2tp_id < 0)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG(3, 0, 0, "Deleting all kernel %ss\n", name);
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
|
||||
req.nh.nlmsg_type = genl_l2tp_id;
|
||||
req.nh.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_DUMP;
|
||||
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.glh));
|
||||
|
||||
req.glh.cmd = cmd;
|
||||
req.glh.version = L2TP_GENL_VERSION;
|
||||
|
||||
assert(req.nh.nlmsg_len < sizeof(req));
|
||||
|
||||
if (genetlink_send(&req.nh) < 0)
|
||||
{
|
||||
LOG(2, 0, 0, "Can't delete %ss: %s\n", name, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
seqnum = genlseqnum;
|
||||
|
||||
/* 1 for receiving "done" */
|
||||
int nitems = 1;
|
||||
int done = 0;
|
||||
|
||||
while (done < nitems)
|
||||
{
|
||||
ssize_t size = genetlink_recv(&req, sizeof(req));
|
||||
if (size < 0)
|
||||
{
|
||||
LOG(2, 0, 0, "Can't receive answer for %s deletion: %s\n", name, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Iterate over all answers
|
||||
struct nlmsghdr *nh;
|
||||
for (nh = &req.nh; size; nh = NLMSG_NEXT(nh, size))
|
||||
{
|
||||
if (!NLMSG_OK(nh, size))
|
||||
{
|
||||
LOG(2, 0, 0, "Short netlink answer: %d vs %zd\n", nh->nlmsg_len, size);
|
||||
break;
|
||||
}
|
||||
|
||||
if (nh->nlmsg_type == NLMSG_NOOP)
|
||||
{
|
||||
// Ignore
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nh->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
done++;
|
||||
if (done < nitems)
|
||||
LOG(3, 0, 0, "Done queueing, still %d/%d %ss deletion pending\n", done, nitems, name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nh->nlmsg_seq != seqnum)
|
||||
{
|
||||
// Consume acknoledgments of deletions.
|
||||
netlink_handle_ack(nh, 1, 0, NULL);
|
||||
done++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Getting more items
|
||||
if (nh->nlmsg_type != genl_l2tp_id)
|
||||
{
|
||||
LOG(2, 0, 0, "Unexpected generic netlink answer %d\n", req.nh.nlmsg_type);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nh->nlmsg_len < NLMSG_HDRLEN + GENL_HDRLEN)
|
||||
{
|
||||
LOG(2, 0, 0, "Short answer for l2tp netlink name\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t ret;
|
||||
if (genetlink_getattr(nh, id1, &ret, sizeof(ret)) != 0)
|
||||
LOG(2, 0, 0, "Did not get %s ID\n", name);
|
||||
else
|
||||
{
|
||||
if (!id2)
|
||||
{
|
||||
delete_one(ret, 0);
|
||||
nitems++;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t ret2;
|
||||
if (genetlink_getattr(nh, id2, &ret2, sizeof(ret2)) != 0)
|
||||
LOG(2, 0, 0, "Did not get %s ID2\n", name);
|
||||
else
|
||||
{
|
||||
// Queue deletion for this
|
||||
delete_one(ret, ret2);
|
||||
nitems++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG(3, 0, 0, "Done deleting %ss\n", name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Create tunnel in kernel
|
||||
static int create_kernel_tunnel(uint32_t tid, uint32_t peer_tid)
|
||||
|
|
@ -529,8 +655,8 @@ static int create_kernel_tunnel(uint32_t tid, uint32_t peer_tid)
|
|||
}
|
||||
|
||||
//
|
||||
// Delete tunnel in kernel
|
||||
static int delete_kernel_tunnel(uint32_t tid)
|
||||
// Queue deleting tunnel in kernel
|
||||
static int queue_delete_kernel_tunnel(uint32_t tid)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr nh;
|
||||
|
|
@ -565,6 +691,23 @@ static int delete_kernel_tunnel(uint32_t tid)
|
|||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Delete tunnel in kernel
|
||||
static int delete_kernel_tunnel(uint32_t tid)
|
||||
{
|
||||
int ret = queue_delete_kernel_tunnel(tid);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr nh;
|
||||
struct genlmsghdr glh;
|
||||
char data[64];
|
||||
} req;
|
||||
|
||||
ssize_t size = genetlink_recv(&req, sizeof(req));
|
||||
if (size < 0)
|
||||
{
|
||||
|
|
@ -577,6 +720,20 @@ static int delete_kernel_tunnel(uint32_t tid)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Clear all existing tunnels
|
||||
//
|
||||
// Unfortunately, tunnels survive us, so we have to drop any tunnel left from a
|
||||
// previous instance that might have crashed.
|
||||
static void delete_one_kernel_tunnel(uint32_t id1, uint32_t id2)
|
||||
{
|
||||
queue_delete_kernel_tunnel(id1);
|
||||
}
|
||||
static void delete_kernel_tunnels(void)
|
||||
{
|
||||
delete_kernel_items("tunnel", L2TP_CMD_TUNNEL_GET, L2TP_ATTR_CONN_ID, L2TP_ATTR_NONE, delete_one_kernel_tunnel);
|
||||
}
|
||||
|
||||
//
|
||||
// Create session in kernel
|
||||
static int create_kernel_session(uint32_t tid, uint32_t peer_tid, uint32_t sid, uint32_t peer_sid)
|
||||
|
|
@ -632,8 +789,8 @@ static int create_kernel_session(uint32_t tid, uint32_t peer_tid, uint32_t sid,
|
|||
}
|
||||
|
||||
//
|
||||
// Delete session in kernel
|
||||
static int delete_kernel_session(uint32_t tid, uint32_t sid)
|
||||
// Queue deleting session in kernel
|
||||
static int queue_delete_kernel_session(uint32_t tid, uint32_t sid)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr nh;
|
||||
|
|
@ -669,6 +826,23 @@ static int delete_kernel_session(uint32_t tid, uint32_t sid)
|
|||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Delete session in kernel
|
||||
static int delete_kernel_session(uint32_t tid, uint32_t sid)
|
||||
{
|
||||
int ret = queue_delete_kernel_session(tid, sid);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr nh;
|
||||
struct genlmsghdr glh;
|
||||
char data[64];
|
||||
} req;
|
||||
|
||||
ssize_t size = genetlink_recv(&req, sizeof(req));
|
||||
if (size < 0)
|
||||
{
|
||||
|
|
@ -681,6 +855,20 @@ static int delete_kernel_session(uint32_t tid, uint32_t sid)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Clear all existing sessions
|
||||
//
|
||||
// Unfortunately, sessions survive us, so we have to drop any session left from a
|
||||
// previous instance that might have crashed.
|
||||
static void delete_one_kernel_session(uint32_t id1, uint32_t id2)
|
||||
{
|
||||
queue_delete_kernel_session(id2, id1);
|
||||
}
|
||||
static void delete_kernel_sessions(void)
|
||||
{
|
||||
delete_kernel_items("session", L2TP_CMD_SESSION_GET, L2TP_ATTR_SESSION_ID, L2TP_ATTR_CONN_ID, delete_one_kernel_session);
|
||||
}
|
||||
|
||||
//
|
||||
// Create the kernel PPPoX socket
|
||||
static int create_ppp_socket(int udp_fd, uint32_t tid, uint32_t peer_tid, uint32_t sid, uint32_t peer_sid, const struct sockaddr *dst, socklen_t addrlen)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue