dwmstatus-mitm.c - sites - public wiki contents of suckless.org | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
dwmstatus-mitm.c (3958B) | |
--- | |
1 /* Here is a helper function that warns you if someone tries to sniff yo… | |
2 * network traffic (i.e. a Man-In-The-Middle attack ran against you than… | |
3 * to ARP cache poisoning). | |
4 * | |
5 * It must be called regularly because it monitors changes in the ARP ta… | |
6 * If a host got a new MAC address, it will alert during ALERT_TIMEOUT s… | |
7 * If the MAC address remains the same, it assumes it is just a new host. | |
8 * Otherwise, if it keep changing, it will keep on alerting. | |
9 * | |
10 * Returns true on success, false otherwise. | |
11 * | |
12 * Written by vladz (vladz AT devzero.fr). | |
13 * Updated by mephesto1337 ( dwm-status AT junk-mail.fr ) | |
14 */ | |
15 | |
16 #include <arpa/inet.h> | |
17 #include <linux/if_ether.h> | |
18 #include <netinet/in.h> | |
19 #include <stdbool.h> | |
20 #include <stdint.h> | |
21 #include <stdio.h> | |
22 #include <stdlib.h> | |
23 #include <string.h> | |
24 #include <time.h> | |
25 | |
26 | |
27 // Some useful macros | |
28 #define CHK(expr, cond) \ | |
29 do { \ | |
30 if ( (expr) cond ) { \ | |
31 fprintf(stderr, "%s failed", #expr); \ | |
32 goto fail; \ | |
33 } \ | |
34 } while ( 0 ) | |
35 | |
36 #define CHK_NEG(expr) CHK((long)(expr), < 0L) | |
37 #define CHK_FALSE(expr) CHK(!!(expr), == false) | |
38 #define CHK_NULL(expr) CHK(expr, == NULL) | |
39 #define SAFE_FREE(func, ptr) \ | |
40 do { \ | |
41 if ( ptr != NULL ) { \ | |
42 func(ptr); \ | |
43 } \ | |
44 ptr = NULL; \ | |
45 } while ( 0 ) | |
46 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) | |
47 | |
48 #define ALERT_TIMEOUT ((time_t)40L) // In seconds | |
49 | |
50 /* The hard maximum number of entries kept in the ARP cache is obtained … | |
51 * "sysctl net.ipv4.neigh.default.gc_thresh3" (see arp(7)). Default val… | |
52 * for Linux is 1024. | |
53 */ | |
54 #define MAX_ARP_CACHE_ENTRIES 1024 | |
55 | |
56 | |
57 struct ether_ip_s { | |
58 union { | |
59 uint8_t mac[ETH_ALEN]; | |
60 unsigned long lmac; | |
61 }; | |
62 time_t last_changed; | |
63 in_addr_t ip; | |
64 }; | |
65 | |
66 struct ether_ip_s table[MAX_ARP_CACHE_ENTRIES]; | |
67 size_t table_size = 0; | |
68 | |
69 | |
70 bool lookup_and_insert(const struct ether_ip_s *new); | |
71 | |
72 bool check_arp_table(char *message, size_t len) { | |
73 FILE *f; | |
74 struct ether_ip_s tmp; | |
75 char ip_address[32]; | |
76 char mac_address[32]; | |
77 | |
78 snprintf(message, len, "ARP table OK"); | |
79 CHK_NULL(f = fopen("/proc/net/arp", "r")); | |
80 time(&tmp.last_changed); | |
81 fscanf(f, "%*[^\n]\n"); | |
82 while ( !feof(f) ) { | |
83 CHK(fscanf(f, "%s%*[ ]0x%*x%*[ ]0x%*x%*[ ]%[a-f0-9:]%*[^\n]\n", … | |
84 CHK_NEG(inet_pton(AF_INET, ip_address, &tmp.ip)); | |
85 | |
86 tmp.lmac = 0UL; | |
87 CHK(sscanf( | |
88 mac_address, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", | |
89 &tmp.mac[0], &tmp.mac[1], &tmp.mac[2], &tmp.mac[3], &tmp.mac… | |
90 ), != 6); | |
91 | |
92 if ( ! lookup_and_insert(&tmp) ) { | |
93 snprintf(message, len, "Possible MITM attack, please check %… | |
94 break; | |
95 } | |
96 } | |
97 SAFE_FREE(fclose, f); | |
98 return true; | |
99 | |
100 fail: | |
101 SAFE_FREE(fclose, f); | |
102 snprintf(message, len, "ARP table ???"); | |
103 return false; | |
104 } | |
105 | |
106 bool lookup_and_insert(const struct ether_ip_s *new) { | |
107 for ( size_t i = 0; i < table_size; i++ ) { | |
108 if ( table[i].ip == new->ip ) { | |
109 if ( table[i].lmac != new->lmac ) { | |
110 if ( table[i].last_changed + ALERT_TIMEOUT > new->last_c… | |
111 return false; | |
112 } else { | |
113 // Update the DB, it must be a new host | |
114 table[i].lmac = new->lmac; | |
115 table[i].last_changed = new->last_changed; | |
116 return true; | |
117 } | |
118 } else { | |
119 // Update last seen | |
120 table[i].last_changed = new->last_changed; | |
121 return true; | |
122 } | |
123 } | |
124 } | |
125 | |
126 if ( table_size < ARRAY_SIZE(table) ) { | |
127 memcpy(&table[table_size], new, sizeof(struct ether_ip_s)); | |
128 table_size++; | |
129 } else { | |
130 // To big, let's restart from the begining | |
131 table_size = 0; | |
132 return false; | |
133 } | |
134 | |
135 return true; | |
136 } |