From a22295d80415ecc1c5dd0576fe024ab626ab8c0f Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sun, 21 Jan 2024 02:45:44 +0100 Subject: [PATCH] Fasten quitting l2tp game Drop routes as quickly as possible to lose as few packets as possible in the meanwhile. --- cluster.c | 24 +++++--------- l2tpns.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ l2tpns.h | 1 + 3 files changed, 105 insertions(+), 16 deletions(-) diff --git a/cluster.c b/cluster.c index ddfc1fe..d4a7a8a 100644 --- a/cluster.c +++ b/cluster.c @@ -435,8 +435,7 @@ static void send_heartbeat(int seq, uint8_t *data, int size) if (size > sizeof(past_hearts[0].data)) { LOG(0, 0, 0, "Tried to heartbeat something larger than the maximum packet!\n"); - kill(0, SIGTERM); - exit(1); + crash(); } i = seq % HB_HISTORY_SIZE; past_hearts[i].seq = seq; @@ -903,8 +902,7 @@ static int hb_add_type(uint8_t **p, int type, int id) break; default: LOG(0, 0, 0, "Found an invalid type in heart queue! (%d)\n", type); - kill(0, SIGTERM); - exit(1); + crash(); } return 0; } @@ -951,8 +949,7 @@ void cluster_heartbeat() if (p > (buff + sizeof(buff))) { // Did we somehow manage to overun the buffer? LOG(0, 0, 0, "FATAL: Overran the heartbeat buffer! This is fatal. Exiting. (size %d)\n", (int) (p - buff)); - kill(0, SIGTERM); - exit(1); + crash(); } // @@ -1011,8 +1008,7 @@ void cluster_heartbeat() // Did we do something wrong? if (p > (buff + sizeof(buff))) { // Did we somehow manage to overun the buffer? LOG(0, 0, 0, "Overran the heartbeat buffer now! This is fatal. Exiting. (size %d)\n", (int) (p - buff)); - kill(0, SIGTERM); - exit(1); + crash(); } LOG(4, 0, 0, "Sending v%d heartbeat #%d, change #%" PRIu64 " with %d changes " @@ -1960,8 +1956,7 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t LOG(0, 0, 0, "They've seen more state changes (%" PRIu64 " vs my %" PRIu64 ") so I'm gone!\n", h->table_version, config->cluster_table_version); - kill(0, SIGTERM); - exit(1); + crash(); } if (h->table_version < config->cluster_table_version) @@ -1969,8 +1964,7 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t if (basetime > h->basetime) { LOG(0, 0, 0, "They're an older master than me so I'm gone!\n"); - kill(0, SIGTERM); - exit(1); + crash(); } if (basetime < h->basetime) @@ -1978,8 +1972,7 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t if (my_address < addr) { // Tie breaker. LOG(0, 0, 0, "They're a higher IP address than me, so I'm gone!\n"); - kill(0, SIGTERM); - exit(1); + crash(); } // @@ -2366,8 +2359,7 @@ int processcluster(uint8_t *data, int size, in_addr_t addr) } LOG(0, 0, 0, "Received a valid C_KILL: I'm going to die now.\n"); - kill(0, SIGTERM); - exit(0); // Lets be paranoid; + crash(); return -1; // Just signalling the compiler. case C_HEARTBEAT: diff --git a/l2tpns.c b/l2tpns.c index 378e6fe..e5e877a 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -2119,6 +2119,66 @@ static int setupif(int ifidx, uint32_t mru, int config_addr) return 0; } +// +// Quickly drop the gateway from the interface +static int disableif(int ifidx) +{ + struct { + // interface setting + struct nlmsghdr nh; + union { + struct ifinfomsg ifinfo; + struct ifaddrmsg ifaddr; + } ifmsg; + char rtdata[32]; // 32 should be enough + } req; + in_addr_t ip; + + memset(&req, 0, sizeof(req)); + + req.nh.nlmsg_type = RTM_DELADDR; + req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_MULTI; + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr)); + + req.ifmsg.ifaddr.ifa_family = AF_INET; + req.ifmsg.ifaddr.ifa_prefixlen = 32; + req.ifmsg.ifaddr.ifa_scope = RT_SCOPE_UNIVERSE; + req.ifmsg.ifaddr.ifa_index = ifidx; + + if (config->nbmultiaddress > 1) + { + int i; + for (i = 0; i < config->nbmultiaddress ; i++) + { + ip = config->iftun_n_address[i]; + rtnetlink_addattr(&req.nh, IFA_LOCAL, &ip, sizeof(ip)); + if (rtnetlink_send(&req.nh) < 0) + return -1; + } + } + else + { + if (config->iftun_address) + ip = config->iftun_address; + else + ip = 0x01010101; // 1.1.1.1 + rtnetlink_addattr(&req.nh, IFA_LOCAL, &ip, sizeof(ip)); + + if (rtnetlink_send(&req.nh) < 0) + return -1; + } + + memset(&req, 0, sizeof(req)); + + req.nh.nlmsg_type = NLMSG_DONE; + req.nh.nlmsg_len = NLMSG_LENGTH(0); + + if (rtnetlink_send(&req.nh) < 0) + return -1; + + return 0; +} + // set up LAC UDP ports static int initlacudp(int *pudpfd, in_addr_t ip_dest, uint16_t port_dest) { @@ -3821,6 +3881,33 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha } } +static void drop_routes(void) +{ + unsigned i; + + LOG(1, 0, 0, "Disabling receiving l2tp\n"); + // Disable receiving l2tp trafic first since we don't forward to master any more + disableif(tunidx); + LOG(1, 0, 0, "Dropping routes\n"); + // Disable receiving Internet trafic + for (i = 1; i <= config->cluster_highest_sessionid ; ++i) + { + routesset(i, &session[i], 0); + routes6set(i, &session[i], 0); + } +} + +// +// We ended up in an odd state, better stop here as quickly as possible before +// causing trouble to the rest of the cluster +// +void crash(void) +{ + kill(0, SIGTERM); + drop_routes(); + exit(1); +} + // read and process packet on tunnel (UDP) void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexudpfd) { @@ -6017,6 +6104,7 @@ static void mainloop(void) } } } + LOG(1, 0, 0, "Leaving...\n"); // Are we the master and shutting down?? if (config->cluster_iam_master) @@ -6032,6 +6120,14 @@ static void mainloop(void) // // Important!!! We MUST not process any packets past this point! + // + + // + // Now drop routes as quickly as possible to lose as few packets as + // possible in the meanwhile + // + drop_routes(); + LOG(1, 0, 0, "Shutdown complete\n"); } diff --git a/l2tpns.h b/l2tpns.h index 33e9f9a..7c5ad72 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -1037,6 +1037,7 @@ void throttle_session(sessionidt s, int rate_in, int rate_out); int load_tunnel(tunnelidt, tunnelt *); int load_session(sessionidt, sessiont *); void become_master(void); // We're the master; kick off any required master initializations. +void crash(void); // We messed up. Die. // cli.c