DEADSOFTWARE

Game: Use proper syntax of sets for game options instead of raw bitwise operations
[d2df-sdl.git] / src / mastersrv / master.c
index 6bb4ffd22ef92de2ae8e551a4a32c1d0d948f2b1..c68d59c1042f9b090632971b5e696648df28ec3e 100644 (file)
@@ -549,6 +549,30 @@ static void ban_free_list(void) {
   banlist = NULL;
 }
 
+static bool ban_record_remove_addr(const enet_uint32 host, const enet_uint32 mask) {
+  for (ban_record_t *b = banlist; b; b = b->next) {
+    if ((b->host == host) && (b->mask == mask)) {
+      if (b == banlist)
+        banlist = b->next;
+      if (b->next) b->next->prev = b->prev;
+      if (b->prev) b->prev->next = b->next;
+      free(b);
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool ban_record_remove_ip(const char *ip) {
+  enet_uint32 mask = 0;
+  const enet_uint32 host = ban_parse_ip_mask(ip, &mask);
+  if (!host) {
+    u_log(LOG_ERROR, "unban: `%s` is not a valid address", ip);
+    return NULL;
+  }
+  return ban_record_remove_addr(host, mask);
+}
+
 static void ban_load_list(const char *fname) {
   FILE *f = fopen(fname, "r");
   if (!f) {
@@ -567,14 +591,14 @@ static void ban_load_list(const char *fname) {
       continue;
 
     char ip[21] = { 0 }; // optionally includes the "/nn" prefix length at the end
-    int64_t exp64 = 0;
+    int expd = 0;
     int count = 0;
-    if (sscanf(ln, "%20s %lld %d", ip, &exp64, &count) < 3) {
+    if (sscanf(ln, "%20s %d %d", ip, &expd, &count) < 3) {
       u_log(LOG_ERROR, "banlist: malformed line: `%s`", ln);
       continue;
     }
 
-    const time_t exp = (time_t)exp64; // shut up gcc
+    const time_t exp = (time_t)expd; // shut up gcc
     if (ban_record_add_ip(ip, count, exp))
       u_log(LOG_NOTE, "banlist: banned %s until %s (ban level %d)", ip, u_strtime(exp), count);
   }
@@ -591,7 +615,7 @@ static void ban_save_list(const char *fname) {
 
   for (ban_record_t *rec = banlist; rec; rec = rec->next) {
     if (rec->ban_count)
-      fprintf(f, "%s/%u %lld %d\n", u_iptostr(rec->host), u_masktoprefix(rec->mask), (int64_t)rec->cur_ban, rec->ban_count);
+      fprintf(f, "%s/%u %d %d\n", u_iptostr(rec->host), u_masktoprefix(rec->mask), (int)rec->cur_ban, rec->ban_count);
   }
 
   fclose(f);
@@ -657,6 +681,15 @@ static void ban_add(const enet_uint32 host, const char *reason) {
     cl_last_addr = 0;
 }
 
+static void ban_remove_mask(const enet_uint32 host, const enet_uint32 mask) {
+  if (!ban_record_remove_addr(host, mask)) {
+    u_log(LOG_ERROR, "could not find %s in ban list", u_iptostr(host));
+    return;
+  }
+  u_log(LOG_NOTE, "unbanned %s", u_iptostr(host));
+  ban_save_list(MS_BAN_FILE);
+}
+
 static inline void ban_peer(ENetPeer *peer, const char *reason) {
   if (peer) {
     ban_add(peer->address.host, reason);
@@ -715,6 +748,15 @@ static void io_read_commands(void) {
       return;
     }
     ban_add_mask(host, mask, "banned by console");
+  } else if (!strncmp(cmd, "unban ", 6)) {
+    const char *ip = u_strstrip(cmd + 6); // skip "unban "
+    enet_uint32 mask = 0;
+    enet_uint32 host = ban_parse_ip_mask(ip, &mask);
+    if (!host) {
+      u_log(LOG_ERROR, "ban: `%s` is not a valid address", ip);
+      return;
+    }
+    ban_remove_mask(host, mask);
   } else if (!strncmp(cmd, "reload", 6)) {
     u_log(LOG_WARN, "reloading banlist");
     ban_free_list();