|
|
@ -3,6 +3,7 @@ |
|
|
|
#include <string.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <stdio.h> |
|
|
|
#include <arpa/inet.h> |
|
|
|
|
|
|
|
#define DESTROY_STR_POOL(etype, ppool) \ |
|
|
|
etype *elem, *tmp; \ |
|
|
@ -517,3 +518,277 @@ bool port_filters_deny_if_empty(struct port_filters_head *head) |
|
|
|
if (LIST_FIRST(head)) return true; |
|
|
|
return pf_parse("0",&pf) && port_filter_add(head,&pf); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct blob_item *blob_collection_add(struct blob_collection_head *head) |
|
|
|
{ |
|
|
|
struct blob_item *entry = calloc(1,sizeof(struct blob_item)); |
|
|
|
if (entry) |
|
|
|
{ |
|
|
|
// insert to the end
|
|
|
|
struct blob_item *itemc,*iteml=LIST_FIRST(head); |
|
|
|
if (iteml) |
|
|
|
{ |
|
|
|
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc; |
|
|
|
LIST_INSERT_AFTER(iteml, entry, next); |
|
|
|
} |
|
|
|
else |
|
|
|
LIST_INSERT_HEAD(head, entry, next); |
|
|
|
} |
|
|
|
return entry; |
|
|
|
} |
|
|
|
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve) |
|
|
|
{ |
|
|
|
struct blob_item *entry = calloc(1,sizeof(struct blob_item)); |
|
|
|
if (!entry) return NULL; |
|
|
|
if (!(entry->data = malloc(size+size_reserve))) |
|
|
|
{ |
|
|
|
free(entry); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
if (data) memcpy(entry->data,data,size); |
|
|
|
entry->size = size; |
|
|
|
entry->size_buf = size+size_reserve; |
|
|
|
|
|
|
|
// insert to the end
|
|
|
|
struct blob_item *itemc,*iteml=LIST_FIRST(head); |
|
|
|
if (iteml) |
|
|
|
{ |
|
|
|
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc; |
|
|
|
LIST_INSERT_AFTER(iteml, entry, next); |
|
|
|
} |
|
|
|
else |
|
|
|
LIST_INSERT_HEAD(head, entry, next); |
|
|
|
|
|
|
|
return entry; |
|
|
|
} |
|
|
|
|
|
|
|
void blob_collection_destroy(struct blob_collection_head *head) |
|
|
|
{ |
|
|
|
struct blob_item *entry; |
|
|
|
while ((entry = LIST_FIRST(head))) |
|
|
|
{ |
|
|
|
LIST_REMOVE(entry, next); |
|
|
|
free(entry->extra); |
|
|
|
free(entry->extra2); |
|
|
|
free(entry->data); |
|
|
|
free(entry); |
|
|
|
} |
|
|
|
} |
|
|
|
bool blob_collection_empty(const struct blob_collection_head *head) |
|
|
|
{ |
|
|
|
return !LIST_FIRST(head); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void ipcache_item_touch(ip_cache_item *item) |
|
|
|
{ |
|
|
|
time(&item->last); |
|
|
|
} |
|
|
|
static void ipcache_item_init(ip_cache_item *item) |
|
|
|
{ |
|
|
|
ipcache_item_touch(item); |
|
|
|
item->hostname = NULL; |
|
|
|
} |
|
|
|
static void ipcache_item_destroy(ip_cache_item *item) |
|
|
|
{ |
|
|
|
free(item->hostname); |
|
|
|
} |
|
|
|
|
|
|
|
static void ipcache4Destroy(ip_cache4 **ipcache) |
|
|
|
{ |
|
|
|
ip_cache4 *elem, *tmp; |
|
|
|
HASH_ITER(hh, *ipcache, elem, tmp) |
|
|
|
{ |
|
|
|
HASH_DEL(*ipcache, elem); |
|
|
|
ipcache_item_destroy(&elem->data); |
|
|
|
free(elem); |
|
|
|
} |
|
|
|
} |
|
|
|
static void ipcache4Key(ip4if *key, const struct in_addr *a) |
|
|
|
{ |
|
|
|
memset(key,0,sizeof(*key)); // make sure everything is zero
|
|
|
|
key->addr = *a; |
|
|
|
} |
|
|
|
static ip_cache4 *ipcache4Find(ip_cache4 *ipcache, const struct in_addr *a) |
|
|
|
{ |
|
|
|
ip_cache4 *entry; |
|
|
|
struct ip4if key; |
|
|
|
|
|
|
|
ipcache4Key(&key,a); |
|
|
|
HASH_FIND(hh, ipcache, &key, sizeof(key), entry); |
|
|
|
return entry; |
|
|
|
} |
|
|
|
static ip_cache4 *ipcache4Add(ip_cache4 **ipcache, const struct in_addr *a) |
|
|
|
{ |
|
|
|
// avoid dups
|
|
|
|
ip_cache4 *entry = ipcache4Find(*ipcache,a); |
|
|
|
if (entry) return entry; // already included
|
|
|
|
|
|
|
|
entry = malloc(sizeof(ip_cache4)); |
|
|
|
if (!entry) return NULL; |
|
|
|
ipcache4Key(&entry->key,a); |
|
|
|
|
|
|
|
oom = false; |
|
|
|
HASH_ADD(hh, *ipcache, key, sizeof(entry->key), entry); |
|
|
|
if (oom) { free(entry); return NULL; } |
|
|
|
|
|
|
|
ipcache_item_init(&entry->data); |
|
|
|
|
|
|
|
return entry; |
|
|
|
} |
|
|
|
static void ipcache4Print(ip_cache4 *ipcache) |
|
|
|
{ |
|
|
|
char s_ip[16]; |
|
|
|
time_t now; |
|
|
|
ip_cache4 *ipc, *tmp; |
|
|
|
|
|
|
|
time(&now); |
|
|
|
HASH_ITER(hh, ipcache , ipc, tmp) |
|
|
|
{ |
|
|
|
*s_ip=0; |
|
|
|
inet_ntop(AF_INET, &ipc->key.addr, s_ip, sizeof(s_ip)); |
|
|
|
printf("%s : hostname=%s now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void ipcache6Destroy(ip_cache6 **ipcache) |
|
|
|
{ |
|
|
|
ip_cache6 *elem, *tmp; |
|
|
|
HASH_ITER(hh, *ipcache, elem, tmp) |
|
|
|
{ |
|
|
|
HASH_DEL(*ipcache, elem); |
|
|
|
ipcache_item_destroy(&elem->data); |
|
|
|
free(elem); |
|
|
|
} |
|
|
|
} |
|
|
|
static void ipcache6Key(ip6if *key, const struct in6_addr *a) |
|
|
|
{ |
|
|
|
memset(key,0,sizeof(*key)); // make sure everything is zero
|
|
|
|
key->addr = *a; |
|
|
|
} |
|
|
|
static ip_cache6 *ipcache6Find(ip_cache6 *ipcache, const struct in6_addr *a) |
|
|
|
{ |
|
|
|
ip_cache6 *entry; |
|
|
|
ip6if key; |
|
|
|
|
|
|
|
ipcache6Key(&key,a); |
|
|
|
HASH_FIND(hh, ipcache, &key, sizeof(key), entry); |
|
|
|
return entry; |
|
|
|
} |
|
|
|
static ip_cache6 *ipcache6Add(ip_cache6 **ipcache, const struct in6_addr *a) |
|
|
|
{ |
|
|
|
// avoid dups
|
|
|
|
ip_cache6 *entry = ipcache6Find(*ipcache,a); |
|
|
|
if (entry) return entry; // already included
|
|
|
|
|
|
|
|
entry = malloc(sizeof(ip_cache6)); |
|
|
|
if (!entry) return NULL; |
|
|
|
ipcache6Key(&entry->key,a); |
|
|
|
|
|
|
|
oom = false; |
|
|
|
HASH_ADD(hh, *ipcache, key, sizeof(entry->key), entry); |
|
|
|
if (oom) { free(entry); return NULL; } |
|
|
|
|
|
|
|
ipcache_item_init(&entry->data); |
|
|
|
|
|
|
|
return entry; |
|
|
|
} |
|
|
|
static void ipcache6Print(ip_cache6 *ipcache) |
|
|
|
{ |
|
|
|
char s_ip[40]; |
|
|
|
time_t now; |
|
|
|
ip_cache6 *ipc, *tmp; |
|
|
|
|
|
|
|
time(&now); |
|
|
|
HASH_ITER(hh, ipcache , ipc, tmp) |
|
|
|
{ |
|
|
|
*s_ip=0; |
|
|
|
inet_ntop(AF_INET6, &ipc->key.addr, s_ip, sizeof(s_ip)); |
|
|
|
printf("%s : hostname=%s now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void ipcacheDestroy(ip_cache *ipcache) |
|
|
|
{ |
|
|
|
ipcache4Destroy(&ipcache->ipcache4); |
|
|
|
ipcache6Destroy(&ipcache->ipcache6); |
|
|
|
} |
|
|
|
void ipcachePrint(ip_cache *ipcache) |
|
|
|
{ |
|
|
|
ipcache4Print(ipcache->ipcache4); |
|
|
|
ipcache6Print(ipcache->ipcache6); |
|
|
|
} |
|
|
|
|
|
|
|
ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6) |
|
|
|
{ |
|
|
|
ip_cache4 *ipcache4; |
|
|
|
ip_cache6 *ipcache6; |
|
|
|
if (a4) |
|
|
|
{ |
|
|
|
if ((ipcache4 = ipcache4Add(&ipcache->ipcache4,a4))) |
|
|
|
{ |
|
|
|
ipcache_item_touch(&ipcache4->data); |
|
|
|
return &ipcache4->data; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (a6) |
|
|
|
{ |
|
|
|
if ((ipcache6 = ipcache6Add(&ipcache->ipcache6,a6))) |
|
|
|
{ |
|
|
|
ipcache_item_touch(&ipcache6->data); |
|
|
|
return &ipcache6->data; |
|
|
|
} |
|
|
|
} |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
static void ipcache4_purge(ip_cache4 **ipcache, time_t lifetime) |
|
|
|
{ |
|
|
|
ip_cache4 *elem, *tmp; |
|
|
|
time_t now = time(NULL); |
|
|
|
HASH_ITER(hh, *ipcache, elem, tmp) |
|
|
|
{ |
|
|
|
if (now >= (elem->data.last + lifetime)) |
|
|
|
{ |
|
|
|
HASH_DEL(*ipcache, elem); |
|
|
|
ipcache_item_destroy(&elem->data); |
|
|
|
free(elem); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
static void ipcache6_purge(ip_cache6 **ipcache, time_t lifetime) |
|
|
|
{ |
|
|
|
ip_cache6 *elem, *tmp; |
|
|
|
time_t now = time(NULL); |
|
|
|
HASH_ITER(hh, *ipcache, elem, tmp) |
|
|
|
{ |
|
|
|
if (now >= (elem->data.last + lifetime)) |
|
|
|
{ |
|
|
|
HASH_DEL(*ipcache, elem); |
|
|
|
ipcache_item_destroy(&elem->data); |
|
|
|
free(elem); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
static void ipcache_purge(ip_cache *ipcache, time_t lifetime) |
|
|
|
{ |
|
|
|
if (lifetime) // 0 = no expire
|
|
|
|
{ |
|
|
|
ipcache4_purge(&ipcache->ipcache4, lifetime); |
|
|
|
ipcache6_purge(&ipcache->ipcache6, lifetime); |
|
|
|
} |
|
|
|
} |
|
|
|
static time_t ipcache_purge_prev=0; |
|
|
|
void ipcachePurgeRateLimited(ip_cache *ipcache, time_t lifetime) |
|
|
|
{ |
|
|
|
time_t now = time(NULL); |
|
|
|
// do not purge too often to save resources
|
|
|
|
if (ipcache_purge_prev != now) |
|
|
|
{ |
|
|
|
ipcache_purge(ipcache, lifetime); |
|
|
|
ipcache_purge_prev = now; |
|
|
|
} |
|
|
|
} |
|
|
|