File: whitelist.c

package info (click to toggle)
mxallowd 1.9-1
  • links: PTS
  • area: main
  • in suites: wheezy
  • size: 264 kB
  • sloc: ansic: 858; sh: 213; makefile: 74
file content (146 lines) | stat: -rw-r--r-- 4,037 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
 * mxallowd
 * (c) 2007-2009 Michael Stapelberg
 * 
 * See mxallowd.c for description, website and license information
 *
 */
#include <stdbool.h>
#include <time.h>
#include <malloc.h>
#include <string.h>
#include <pthread.h>

#ifdef PF
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_pflog.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <arpa/inet.h>
#include <net/pfvar.h>
#include <net/pfvar.h>
#include <fcntl.h>
#include <unistd.h>
#endif

#include "mxallowd.h"
#include "log.h"
#define _WHITELIST_INTERNAL
#include "whitelist.h"
#undef _WHITELIST_INTERNAL

bool is_whitelisted(char *ip_address, bool useIt) {
	if (root == NULL)
		return false;

	struct whitelist_entry *cur = root;
	do {
		if (cur->ip_address != NULL && strcmp(cur->ip_address, ip_address) == 0) {
			if (useIt)
				cur->used = true;
			return true;
		}
	} while ((cur = cur->next) != NULL);
	return false;
}

/* 
 * Doesn't free() old entries but invalidates them, they'll get reused 
 *
 * */
void cleanup_whitelist() {
	if (root != NULL) {
		time_t current_time = time(NULL);
		struct whitelist_entry *cur = root;
		do {
			if (cur->ip_address != NULL && (current_time - cur->added) > allow_time) {
				/* If the entry is too old, invalidate it by freeing ip_address */
				slog("Cleaning %s (RDNS: %s) from whitelist (timeout)\n",
					cur->ip_address, (cur->rdns != NULL ? cur->rdns : "unresolvable"));
				if (!cur->is_child) {
					if (cur->used)
						successful_connects++;
					else direct_to_fake++;
				}

				free(cur->ip_address);
				cur->ip_address = NULL;
				if (cur->rdns != NULL) {
					free(cur->rdns);
					cur->rdns = NULL;
				}
			}
		} while ((cur = cur->next) != NULL);
	}
}

/*
 * Adds the given ip address (with rdns if not NULL) to whitelist
 * is_child = flag whether the entry has to be counted as one mailserver
 * or whether it's just another IP of this mailserver
 *
 */
void add_to_whitelist(char *ip_address, char *rdns, bool is_child, int af, const void *source_addr) {
	if (is_whitelisted(ip_address, false))
		return;

	struct whitelist_entry *new_entry = malloc(sizeof(struct whitelist_entry));
	new_entry->next = NULL;
	new_entry->ip_address = strdup(ip_address);
	new_entry->rdns = (rdns != NULL ? strdup(rdns) : NULL);
	new_entry->rdns_tried = (rdns != NULL);
	new_entry->added = time(NULL);
	new_entry->is_child = is_child;
	new_entry->used = false;

	if (root == NULL)
		root = new_entry;
	else {
		struct whitelist_entry *cur = root;
		while (cur->next != NULL && cur->ip_address != NULL)
			cur = cur->next;
		if (cur->ip_address == NULL) {
			/* This is a cleaned up entry, overwrite values */
			cur->ip_address = new_entry->ip_address;
			cur->rdns = new_entry->rdns;
			cur->rdns_tried = new_entry->rdns_tried;
			cur->added = new_entry->added;
			cur->is_child = is_child;
			cur->used = false;
			free(new_entry);
		} else cur->next = new_entry;
	}

#ifdef PF
	struct pfioc_table table;
	struct pfr_addr addr;
	memset(&table, '\0', sizeof(struct pfioc_table));
	memset(&addr, '\0', sizeof(struct pfr_addr));
	table.pfrio_buffer = &addr;
	table.pfrio_esize = sizeof(struct pfr_addr);
	table.pfrio_size = 1;
	strcpy(table.pfrio_table.pfrt_name, "mx-white");
	addr.pfra_af = af;
	addr.pfra_net = (af == AF_INET ? 32 : 128);
	if (af == AF_INET)
		memcpy(&(addr.pfra_ip4addr), ((struct sockaddr_in*)source_addr)->sin_addr, sizeof(struct in_addr));
	else memcpy(&addr.pfra_ip6addr, ((struct sockaddr_in6*)source_addr)->sin6_addr, sizeof(struct in6_addr));

	if (ioctl(pffd, DIOCRADDADDRS, &table) == -1)
		slogerror("Couldn't ioctl() on /dev/pf\n");
	if (table.pfrio_nadd != 1)
		slog("Adding IP to table failed, it probably is already whitelisted\n");
#endif

	if (rdns_whitelist) {
		/* Inform the resolver-thread of the new entry to resolve */
		pthread_mutex_lock(&resolv_thread_mutex);
		pthread_cond_broadcast(&resolv_new_cond);
		pthread_mutex_unlock(&resolv_thread_mutex);
	}
}