main.c (5367B)
1 #include <sys/stat.h> 2 #include <sys/types.h> 3 4 #include <err.h> 5 #include <errno.h> 6 #include <fcntl.h> 7 #include <limits.h> 8 #include <signal.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <unistd.h> 13 14 #include "arg.h" 15 16 #include "attack.h" 17 #include "config.h" 18 #include "fw.h" 19 #include "ip.h" 20 #include "parser.h" 21 #include "queue.h" 22 23 #define BUFSZ 512 24 25 int fd_black; 26 int fd_white; 27 int ignore; 28 int shutdown; 29 char *argv0; 30 31 static char buf[BUFSZ]; 32 SLIST_HEAD(lhead, attacker) head = SLIST_HEAD_INITIALIZER(head); 33 34 void 35 ban(struct attacker *a) 36 { 37 if (a->list != GREY) 38 return; 39 40 a->nban++; 41 if (a->nban >= 0 42 && fw_block(a->ip) 43 && a->nban > max_try) 44 blacklist(a); 45 } 46 47 void 48 unban(struct attacker *a, struct lhead *headp) 49 { 50 struct attacker *ap; 51 52 if (a) { 53 if (fw_unblock(a->ip)) 54 a->last = LLONG_MAX; 55 return; 56 } 57 58 SLIST_FOREACH(ap, headp, attackers) 59 if (ap->list == GREY && isexpire(ap)) 60 if (fw_unblock(ap->ip)) 61 ap->last = LLONG_MAX; 62 } 63 64 void 65 init(struct attacker *a) 66 { 67 strcpy(a->ip, ip); 68 a->nban = -immune_try; 69 a->last = attack; 70 a->list = GREY; 71 } 72 73 /* 74 * XXX readline relies upon the assumption 75 * that a line can be atmost BUFSZ long 76 */ 77 char * 78 readline(int fd) 79 { 80 static char *next; 81 static int rem; 82 int n; 83 84 if (rem) 85 memmove(buf, next, rem); 86 87 if ((n = read(fd, buf+rem, BUFSZ-rem)) == -1) 88 err(1, "read failed"); 89 90 rem += n; 91 for (int i = 0; i < rem; ++i) 92 if (buf[i] == '\n') { 93 buf[i] = '\0'; 94 rem -= i+1; 95 next = (rem == 0) ? NULL : &buf[i+1]; 96 return buf; 97 } 98 99 return NULL; 100 } 101 102 int 103 foverlap(int fd1, int fd2) 104 { 105 FILE *fp1, *fp2; 106 int r1, r2; 107 char buf1[16], buf2[16]; 108 109 fp1 = fdopen(fd1, "r"); 110 if (!fp1) 111 err(1, "fdopen failed"); 112 113 fp2 = fdopen(fd2, "r"); 114 if (!fp2) 115 err(1, "fdopen failed"); 116 117 do { 118 r1 = fscanf(fp1, "%s\n", buf1); 119 if (r1 != EOF) { 120 do { 121 r2 = fscanf(fp2, "%s\n", buf2); 122 if (r2 != EOF 123 && !strcmp(buf1, buf2)) 124 return 1; 125 } while (r2 != EOF); 126 } 127 } while(r1 != EOF); 128 return 0; 129 } 130 131 void 132 cleanup() 133 { 134 struct attacker *prev, *a; 135 136 prev= NULL; 137 SLIST_FOREACH(a, &head, attackers) { 138 if (prev) 139 free(prev); 140 prev = a; 141 } 142 free(prev); 143 } 144 145 void 146 usage(void) 147 { 148 fprintf(stderr, "usage: sdog [-d]\n"); 149 exit(1); 150 } 151 152 void 153 daemon_init(void) 154 { 155 pid_t p; 156 157 if ((p = fork()) == -1) 158 err(1, "fork failed"); 159 else if (p != 0) 160 exit(0); 161 if (setsid() == -1) 162 err(1, "setsid failed"); 163 if (chdir("/etc/gods") == -1) 164 err(1, "chdir failed: %s", "/etc/gods"); 165 umask(0); 166 } 167 168 void 169 terminate(int a) 170 { 171 shutdown = 1; 172 } 173 174 int 175 main(int argc, char **argv) 176 { 177 FILE *fp; 178 char *line; 179 char bf[16]; 180 int debug, fd, found, ret; 181 struct attacker *a; 182 time_t now; 183 184 shutdown = debug = 0; 185 186 ARGBEGIN { 187 case 'd': 188 debug = 1; 189 break; 190 default: 191 usage(); 192 } ARGEND 193 194 if (!debug) 195 daemon_init(); 196 197 signal(SIGHUP, terminate); 198 199 fd = open(sshlog, O_RDONLY); 200 if (fd == -1) 201 err(1, "open failed: %s", sshlog); 202 203 fd_black = open(black_list, O_RDWR | O_CREAT | O_APPEND, 204 S_IRUSR | S_IWUSR); 205 if (fd_black == -1) 206 err(1, "open failed: %s", black_list); 207 208 fd_white = open(white_list, O_RDWR | O_CREAT | O_APPEND, 209 S_IRUSR | S_IWUSR); 210 if (fd_white == -1) 211 err(1, "open failed: %s", white_list); 212 213 if (foverlap(fd_black, fd_white)) 214 errx(1, "blacklist and whitelist are not mutually exclusive."); 215 216 fp = fopen(black_list, "r"); 217 if (!fp) 218 err(1, "fopen failed: %s", black_list); 219 do { 220 ret = fscanf(fp, "%s\n", bf); 221 if (ret == EOF) 222 break; 223 if (!isip(bf)) 224 errx(1, "malformed ip in blacklist"); 225 SLIST_FOREACH(a, &head, attackers) 226 if (!strcmp(a->ip, bf)) 227 errx(1, "duplicate entry found in %s", 228 black_list); 229 a = malloc(sizeof(struct attacker)); 230 if (!a) 231 err(1, "malloc failed"); 232 /* 233 * Attackers generated from blacklist 234 * will have nban and last set to 0 235 */ 236 strcpy(a->ip, bf); 237 a->list = BLACK; 238 fw_block(a->ip); 239 SLIST_INSERT_HEAD(&head, a, attackers); 240 } while (ret != EOF); 241 fclose(fp); 242 243 fp = fopen(white_list, "r"); 244 if (!fp) 245 err(1, "fopen failed: %s", white_list); 246 do { 247 ret = fscanf(fp, "%s\n", bf); 248 if (ret == EOF) 249 break; 250 if (!isip(bf)) 251 errx(1, "malformed ip in whitelist"); 252 SLIST_FOREACH(a, &head, attackers) 253 if (!strcmp(a->ip, bf)) 254 errx(1, "duplicate entry found in %s", 255 white_list); 256 a = malloc(sizeof(struct attacker)); 257 if (!a) 258 err(1, "malloc failed"); 259 /* 260 * Attackers generated from whitelist 261 * will have nban and last set to 0 262 */ 263 strcpy(a->ip, bf); 264 a->list = WHITE; 265 SLIST_INSERT_HEAD(&head, a, attackers); 266 } while (ret != EOF); 267 fclose(fp); 268 269 now = time(NULL); 270 for ( ; ; ) { 271 if (shutdown) 272 break; 273 274 unban(NULL, &head); 275 if ((line = readline(fd)) == NULL) { 276 usleep(5); 277 continue; 278 } 279 280 if (parse(line, now) == -1) { 281 fprintf(stderr, "parse failed\n"); 282 continue; 283 } 284 if (ignore) 285 continue; 286 287 a = NULL; 288 found = 0; 289 if (isattack(statmsg, preauth)) { 290 SLIST_FOREACH(a, &head, attackers) 291 if (!strcmp(a->ip, ip)) { 292 ++found; 293 break; 294 } 295 296 if (!found) { 297 a = malloc(sizeof(struct attacker)); 298 if (!a) 299 err(1, "malloc failed"); 300 init(a); 301 SLIST_INSERT_HEAD(&head, a, attackers); 302 } 303 ban(a); 304 } 305 306 if (islogin(statmsg)) 307 SLIST_FOREACH(a, &head, attackers) 308 if (!strcmp(a->ip, ip)) { 309 printf("attacker deleted\n"); 310 SLIST_REMOVE(&head, a, attacker, attackers); 311 free(a); 312 } 313 } 314 cleanup(); 315 return 0; 316 }