+/*** Internal representation of IPv4/IPv6 addresses ***/
+
+// In network byte order, IPv4 represented as ::ffff:1.2.3.4
+struct addr {
+ u32 a[4];
+};
+
+#define ADDR_BUFSIZE 64
+#define AFMT(_a) ({ char *_buf = alloca(ADDR_BUFSIZE); addr_format(_buf, _a); _buf; })
+
+static bool addr_is_v4(struct addr addr)
+{
+ return !addr.a[0] && !addr.a[1] && addr.a[2] == htonl(0xffff);
+}
+
+static void addr_format(char *buf, struct addr addr)
+{
+ const char *ok;
+ if (addr_is_v4(addr))
+ {
+ struct in_addr in4;
+ in4.s_addr = addr.a[3];
+ ok = inet_ntop(AF_INET, &in4, buf, ADDR_BUFSIZE);
+ }
+ else
+ {
+ struct in6_addr in6;
+ memcpy(&in6, &addr, sizeof(addr));
+ ok = inet_ntop(AF_INET6, &in6, buf, ADDR_BUFSIZE);
+ }
+ if (!ok)
+ snprintf(buf, ADDR_BUFSIZE, "<error %d>", errno);
+}
+
+static bool addr_parse(struct addr *addr, const char *src)
+{
+ struct in_addr a4;
+ struct in6_addr a6;
+
+ if (inet_pton(AF_INET, src, &a4))
+ {
+ addr->a[0] = addr->a[1] = 0;
+ addr->a[2] = htonl(0xffff);
+ addr->a[3] = a4.s_addr;
+ return 1;
+ }
+ else if (inet_pton(AF_INET6, src, &a6))
+ {
+ memcpy(&addr, &a6, 16);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/*** Configuration ***/
+
+static uns max_culprits = 3; // FIXME
+static uns max_failures = 3; // FIXME
+static uns max_idle_time = 600; // FIXME
+static uns max_banned_time = 600; // FIXME
+
+/*** An interface to IP sets ***/