-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathtimer.c
155 lines (133 loc) · 3.84 KB
/
timer.c
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
147
148
149
150
151
152
153
154
155
/**
* timer.c - Run each source IP/dest port pair through the hash table in
* this file to ensure that the packet isn't being flooded.
*/
#include "timer.h"
#include "sdh-proxy.h"
#include <pcap.h>
#include <time.h>
#include "uthash/uthash.h"
#include <pthread.h>
#include <unistd.h>
int timer_enabled = 0;
int pkt_timeout_s = 1;
int pkt_timeout_us = 0;
pkt_t *pkthash = NULL;
pthread_rwlock_t timer_lock;
#define LOOKUP_LENGTH 6
/**
* Compare a packet's last seen time with a given now time, and see if the
* difference is > or < than the pkt_timeout_(u)s values
*
* @param oldtime The 'old' time the packet was last seen
* @param now What is considered to be 'now'
* @return DROP_PACKET or SEND_PACKET accordingly
* */
int timer_drop_packet(struct timeval * oldtime, struct timeval * now)
{
if (oldtime->tv_sec + pkt_timeout_s < now->tv_sec)
{
return SEND_PACKET;
}
else if ( oldtime->tv_sec + pkt_timeout_s == now->tv_sec)
{
if ( oldtime->tv_usec + pkt_timeout_us < now->tv_usec)
return SEND_PACKET;
else
return DROP_PACKET;
}
return DROP_PACKET;
}
/**
* Initialise the r/w lock for the hash table
* */
void timer_init()
{
pthread_rwlock_init(&timer_lock,NULL);
}
/**
* Entry point for a thread.
*
* Cleans out old entries from the hash table every 10*timeout_s
*
* Holds a r/w lock on the hash table for the duration of each iteration
*/
void * timer_purge_old_entries_loop(void * __unused)
{
pkt_t * s, * tmp;
struct timeval now;
while (1)
{
gettimeofday(&now, NULL);
pthread_rwlock_wrlock(&timer_lock);
HASH_ITER(hh, pkthash, s, tmp)
{
// Delete from the table if that packet would be allowed through
if ( timer_drop_packet( &s->lasthit, &now) == SEND_PACKET)
{
HASH_DEL(pkthash, s);
free(s);
}
}
pthread_rwlock_unlock(&timer_lock);
if (pkt_timeout_s == 0)
sleep(2);
else
sleep(10* pkt_timeout_s);
}
}
/**
* Checks if a given source IP and dest port combo has been broadcast in the
* last pkt_timeout ms. This is used to prevent a broadcast storm in case of
* a loop.
*
* IMPORTANT: everything passed in to this function is left in network order.
* We don't care what order it's in, as long as it uniquely represents an
* IP/port combo. Call ntohs() on the port number if it needs using.
*
* @param address The source IP. 4 bytes.
* @param port The destination UDP port. 2 bytes.
* @return DROP_PACKET if the packet has been seen recently. SEND_PACKET if it
* has not.
**/
int timer_check_packet( const bpf_u_int32 * address, const unsigned short int * port )
{
char lookup_addr[LOOKUP_LENGTH]; // put address and port in to here
pkt_t * tmp; // Use this for hash table lookups
// Form lookup string
memcpy(&lookup_addr[0], address, 4);
memcpy(&lookup_addr[0]+sizeof(bpf_u_int32), port, 2);
struct timeval now;
gettimeofday(&now, NULL);
// Check if the packet has been recently sent
pthread_rwlock_rdlock(&timer_lock);
HASH_FIND(hh, pkthash, lookup_addr, LOOKUP_LENGTH ,tmp);
pthread_rwlock_unlock(&timer_lock);
if (tmp)
{
//printf("Found a match in the hash table\n");
// Found a match
if ( timer_drop_packet(&(tmp->lasthit), &now) == SEND_PACKET)
{
// Update time
memcpy(&(tmp->lasthit), &now, sizeof(struct timeval));
return SEND_PACKET;
}
else
{
// Return drop packet - don't update time
return DROP_PACKET;
}
}
else
{
//printf("No match was found in the hash table\n");
tmp = ( pkt_t *)malloc(sizeof(pkt_t));
memcpy(&tmp->ipport,lookup_addr, LOOKUP_LENGTH);
memcpy(&(tmp->lasthit), &now, sizeof(struct timeval));
pthread_rwlock_wrlock(&timer_lock);
HASH_ADD(hh, pkthash, ipport, LOOKUP_LENGTH, tmp);
pthread_rwlock_unlock(&timer_lock);
}
return SEND_PACKET;
}