diff --git a/Makefile b/Makefile
index 980817ec..26691eae 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ include config.mk
UTILS := xdp-filter xdp-loader xdp-dump
ifneq ($(BPFTOOL),)
-UTILS += xdp-bench xdp-monitor xdp-trafficgen xdp-synproxy xdp-dnsrrl xdp-udp xdp-dns xdp-sni
+UTILS += xdp-bench xdp-monitor xdp-trafficgen xdp-synproxy xdp-dnsrrl xdp-udp xdp-dns xdp-sni xdp-geoip
endif
SUBDIRS := lib $(UTILS)
diff --git a/xdp-geoip/Makefile b/xdp-geoip/Makefile
new file mode 100644
index 00000000..637d824d
--- /dev/null
+++ b/xdp-geoip/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+XDP_TARGETS := xdp_geoip.bpf
+BPF_SKEL_TARGETS := $(XDP_TARGETS)
+USER_TARGETS := xdp_geoip
+
+LIB_DIR = ../lib
+
+include $(LIB_DIR)/common.mk
diff --git a/xdp-geoip/xdp_geoip.bpf.c b/xdp-geoip/xdp_geoip.bpf.c
new file mode 100644
index 00000000..b1805109
--- /dev/null
+++ b/xdp-geoip/xdp_geoip.bpf.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2024, BPFire. All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "vmlinux_local.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct ipv4_lpm_key {
+ __u32 prefixlen;
+ __u32 saddr;
+};
+
+struct {
+ __uint(type, BPF_MAP_TYPE_LPM_TRIE);
+ __uint(max_entries, 1000000);
+ __uint(pinning, LIBBPF_PIN_BY_NAME);
+ __uint(map_flags, BPF_F_NO_PREALLOC);
+ __type(key, struct ipv4_lpm_key);
+ __type(value, __u8);
+} geoip_map SEC(".maps");
+
+SEC("xdp")
+int xdp_geoip(struct xdp_md *ctx) {
+ void *data_end = (void *)(long)ctx->data_end;
+ void *data = (void *)(long)ctx->data;
+ struct ethhdr *eth = data;
+ struct iphdr *iph;
+
+ if ((void *)(eth + 1) > data_end)
+ return XDP_PASS;
+
+ if (eth->h_proto != __constant_htons(ETH_P_IP))
+ return XDP_PASS;
+
+ iph = (struct iphdr *)(eth + 1);
+ if ((void *)(iph + 1) > data_end)
+ return XDP_PASS;
+
+ struct ipv4_lpm_key key = {
+ .prefixlen = 32,
+ .saddr = iph->saddr,
+ };
+
+ __u8 *action = bpf_map_lookup_elem(&geoip_map, &key);
+ if (action && *action == 1) {
+ return XDP_DROP;
+ }
+
+ return XDP_PASS;
+}
+
+char _license[] SEC("license") = "GPL";
+
diff --git a/xdp-geoip/xdp_geoip.c b/xdp-geoip/xdp_geoip.c
new file mode 100644
index 00000000..cab30321
--- /dev/null
+++ b/xdp-geoip/xdp_geoip.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2024, BPFire. All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MAP_PATH "/sys/fs/bpf/xdp-geoip/geoip_map"
+#define BATCH_SIZE 1000 // Number of entries per batch
+
+struct ipv4_lpm_key {
+ __u32 prefixlen;
+ __u32 saddr;
+};
+
+// Structure for country code and action
+struct ip_entry {
+ struct ipv4_lpm_key key;
+ __u8 action;
+};
+
+void add_ips_batch(int map_fd, struct ip_entry *entries, size_t count) {
+ struct ipv4_lpm_key keys[BATCH_SIZE];
+ __u8 actions[BATCH_SIZE];
+ for (size_t i = 0; i < count; i++) {
+ keys[i] = entries[i].key;
+ actions[i] = entries[i].action;
+ }
+
+ __u32 num_entries = count;
+ int ret = bpf_map_update_batch(map_fd, keys, actions, &num_entries, NULL);
+ if (ret) {
+ fprintf(stderr, "Batch update failed: %s\n", strerror(errno));
+ } else {
+ printf("Batch update successful\n");
+ }
+}
+
+int main(int argc, char **argv) {
+ if (argc < 3) {
+ printf("Usage: %s \n", argv[0]);
+ return 1;
+ }
+
+ char *enabled_country = argv[2]; // Country code provided from web interface
+
+ // Open the BPF map
+ int map_fd = bpf_obj_get(MAP_PATH);
+ if (map_fd < 0) {
+ perror("bpf_obj_get");
+ return 1;
+ }
+
+ FILE *file = fopen(argv[1], "r");
+ if (!file) {
+ perror("fopen");
+ return 1;
+ }
+
+ struct ip_entry entries[BATCH_SIZE];
+ size_t count = 0;
+
+ char line[256];
+ while (fgets(line, sizeof(line), file)) {
+ // Look for lines that start with "add" and a two-letter country code
+ if (strncmp(line, "add ", 4) == 0) {
+ char *country_code = strtok(line + 4, "v"); // Extract the country code
+ strtok(NULL, " "); // Skip the next token ("hash")
+ char *ip_str = strtok(NULL, " /"); // Extract the IP address
+ char *prefix_str = strtok(NULL, " "); // Extract the prefix length
+
+ // If country code matches the enabled country, add the IP
+ if (country_code && strcmp(country_code, enabled_country) == 0) {
+ if (ip_str && prefix_str) {
+ entries[count].key.prefixlen = atoi(prefix_str);
+ inet_pton(AF_INET, ip_str, &entries[count].key.saddr);
+
+ // Assuming we block IPs from enabled country
+ entries[count].action = 1; // Block
+
+ count++;
+
+ if (count == BATCH_SIZE) {
+ add_ips_batch(map_fd, entries, count);
+ count = 0;
+ }
+ }
+ }
+ }
+ }
+
+ // Process any remaining IPs
+ if (count > 0) {
+ add_ips_batch(map_fd, entries, count);
+ }
+
+ fclose(file);
+ close(map_fd);
+ return 0;
+}
+