example: round out captchas to 5
[rb-79.git] / rb79-ban-ip.c
blob0c736ce3cb6bf62c7472ef93fe84fc12d664437c
1 /*
2 * Copyright (c) 2017, De Rais <derais@cock.li>
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
18 #include <errno.h>
19 #include <locale.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <time.h>
24 #include <unistd.h>
26 #include <sodium.h>
28 #include "macros.h"
29 #include "rb79.h"
31 #include "config.h"
33 const char *program_name = "rb79-ban-ip";
35 /* Show usage message, do not exit */
36 void usage(void)
38 size_t len = strlen(program_name);
40 printf("Usage: %s [ -i individual-ip ] # -i, -f mutually exclusive\n",
41 program_name);
42 printf(" %*s [ -f first-ip -l last-ip ]\n", (int) len, "");
43 printf(" %*s [ -m ban-message ]\n", (int) len, "");
44 printf(" %*s [ -b board-name ] # default: global ban\n",
45 (int) len, "");
46 printf(" %*s [ -u banned-until ] # default: 7 days from now\n",
47 (int) len, "");
50 /* Do the thing */
51 int main(int argc, char **argv)
53 int ret = EINVAL;
54 struct configuration conf = { 0 };
55 int opt = 0;
56 const char *b_arg = 0;
57 size_t board_idx = 0;
58 uint_fast8_t global_ban = 0;
59 const char *first_ip = 0;
60 char *normalized_first_ip = 0;
61 const char *last_ip = 0;
62 char *normalized_last_ip = 0;
63 const char *ban_message = 0;
64 const char *raw_until = 0;
65 time_t until = 0;
67 setlocale(LC_ALL, "");
69 /* Parse options */
70 while ((opt = getopt(argc, argv, "i:f:l:m:u:b:")) != -1) {
71 switch (opt) {
72 case 'b':
74 if (b_arg) {
75 ERROR_MESSAGE("-b already specified");
76 goto done;
79 b_arg = optarg;
80 break;
81 case 'i':
83 if (first_ip) {
84 ERROR_MESSAGE("Only one IP address or"
85 " range may be specified");
86 goto done;
89 first_ip = optarg;
90 last_ip = optarg;
91 break;
92 case 'f':
94 if (first_ip) {
95 ERROR_MESSAGE("Only one IP address or"
96 " range may be specified");
97 goto done;
100 first_ip = optarg;
101 break;
102 case 'l':
104 if (last_ip) {
105 ERROR_MESSAGE("Only one IP address or"
106 " range may be specified");
107 goto done;
110 last_ip = optarg;
111 break;
112 case 'm':
114 if (ban_message) {
115 ERROR_MESSAGE("Only one ban message"
116 " may be specified");
117 goto done;
120 ban_message = optarg;
121 break;
122 case 'u':
124 if (raw_until) {
125 ERROR_MESSAGE("Only one expiry time"
126 " may be specified");
127 goto done;
130 raw_until = optarg;
131 break;
132 default:
133 usage();
134 goto done;
138 if (!first_ip ||
139 !last_ip) {
140 ERROR_MESSAGE("An IP address or range must be specified");
141 usage();
142 goto done;
145 if (!ban_message) {
146 ban_message = "";
149 if (raw_until) {
150 until = (time_t) strtoull(raw_until, 0, 0);
151 } else {
152 until = time(0) + (7 * 24 * 60 * 60);
155 conf = (struct configuration) {
156 /* */
157 .static_www_folder = static_www_folder, /* */
158 .work_path = work_path, /* */
159 .trip_salt = trip_salt, /* */
160 .trip_salt_len = strlen(trip_salt), /* */
161 .boards = boards, /* */
162 .boards_num = NUM_OF(boards), /* */
163 .max_form_data_size = max_form_data_size, /* */
164 .max_file_size = max_file_size, /* */
165 .max_text_len = max_text_len, /* */
166 .filetypes = filetypes, /* */
167 .filetypes_num = NUM_OF(filetypes), /* */
168 .file_description_prog = file_description_prog, /* */
169 .headers = headers, /* */
170 .headers_num = NUM_OF(headers), /* */
171 .challenges = challenges, /* */
172 .challenges_num = NUM_OF(challenges), /* */
173 .wordfilter_inputs = wordfilter_inputs, /* */
174 .wordfilter_inputs_num = NUM_OF(wordfilter_inputs), /* */
177 /* Interpret board */
178 if (!b_arg) {
179 global_ban = 1;
180 } else {
181 board_idx = (size_t) -1;
183 for (size_t j = 0; j < conf.boards_num; ++j) {
184 if (!strcmp(conf.boards[j].name, b_arg)) {
185 board_idx = j;
189 if (board_idx == (size_t) -1) {
190 ERROR_MESSAGE("No board \"%s\" known", b_arg);
191 goto done;
195 /* Interpret IP addresses */
196 if (util_normalize_ip(first_ip, &normalized_first_ip) < 0) {
197 goto done;
200 if (util_normalize_ip(last_ip, &normalized_last_ip) < 0) {
201 goto done;
204 /* Set up a minimal part of the system */
205 if (setup_locks(&conf) < 0) {
206 goto done;
209 if (setup_dbs(&conf) < 0) {
210 goto done;
213 if (setup_write_thread(&conf) < 0) {
214 goto done;
217 ret = db_insert_ban(global_ban, board_idx, normalized_first_ip,
218 normalized_last_ip, ban_message, time(0), until);
219 done:
220 clean_locks();
221 clean_dbs();
222 clean_write_thread();
223 free(normalized_first_ip);
224 free(normalized_last_ip);
226 return ret;