server: let some boards be exempt from /recent
[rb-79.git] / rb79-ban-ip.c
blobd21f2f00546c8146404afa8402dfab6a3040bfd5
1 /*
2 * Copyright (c) 2017-2020, 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
37 usage(void)
39 size_t len = strlen(program_name);
41 printf("Usage: %s [ -i individual-ip ] # -i, -f mutually exclusive\n",
42 program_name);
43 printf(" %*s [ -f first-ip -l last-ip ]\n", (int) len, "");
44 printf(" %*s [ -m ban-message ]\n", (int) len, "");
45 printf(" %*s [ -b board-name ] # default: global ban\n",
46 (int) len, "");
47 printf(" %*s [ -u banned-until ] # default: 7 days from now\n",
48 (int) len, "");
51 /* Do the thing */
52 int
53 main(int argc, char **argv)
55 int ret = EINVAL;
56 struct configuration conf = { 0 };
57 int opt = 0;
58 const char *b_arg = 0;
59 size_t board_idx = 0;
60 uint_fast8_t global_ban = 0;
61 const char *first_ip = 0;
62 char *normalized_first_ip = 0;
63 const char *last_ip = 0;
64 char *normalized_last_ip = 0;
65 const char *ban_message = 0;
66 const char *raw_until = 0;
67 time_t until = 0;
69 setlocale(LC_ALL, "");
71 /* Parse options */
72 while ((opt = getopt(argc, argv, "i:f:l:m:u:b:")) != -1) {
73 switch (opt) {
74 case 'b':
76 if (b_arg) {
77 ERROR_MESSAGE("-b already specified");
78 goto done;
81 b_arg = optarg;
82 break;
83 case 'i':
85 if (first_ip) {
86 ERROR_MESSAGE("Only one IP address or"
87 " range may be specified");
88 goto done;
91 first_ip = optarg;
92 last_ip = optarg;
93 break;
94 case 'f':
96 if (first_ip) {
97 ERROR_MESSAGE("Only one IP address or"
98 " range may be specified");
99 goto done;
102 first_ip = optarg;
103 break;
104 case 'l':
106 if (last_ip) {
107 ERROR_MESSAGE("Only one IP address or"
108 " range may be specified");
109 goto done;
112 last_ip = optarg;
113 break;
114 case 'm':
116 if (ban_message) {
117 ERROR_MESSAGE("Only one ban message"
118 " may be specified");
119 goto done;
122 ban_message = optarg;
123 break;
124 case 'u':
126 if (raw_until) {
127 ERROR_MESSAGE("Only one expiry time"
128 " may be specified");
129 goto done;
132 raw_until = optarg;
133 break;
134 default:
135 usage();
136 goto done;
140 if (!first_ip ||
141 !last_ip) {
142 ERROR_MESSAGE("An IP address or range must be specified");
143 usage();
144 goto done;
147 if (!ban_message) {
148 ban_message = "";
151 if (raw_until) {
152 until = (time_t) strtoull(raw_until, 0, 0);
153 } else {
154 until = time(0) + (7 * 24 * 60 * 60);
157 conf = (struct configuration) {
158 /* */
159 .static_www_folder = static_www_folder, /* */
160 .work_path = work_path, /* */
161 .temp_dir_template = temp_dir_template, /* */
162 .trip_salt = trip_salt, /* */
163 .trip_salt_len = strlen(trip_salt), /* */
164 .boards = boards, /* */
165 .boards_num = NUM_OF(boards), /* */
166 .max_form_data_size = max_form_data_size, /* */
167 .max_file_size = max_file_size, /* */
168 .max_text_len = max_text_len, /* */
169 .filetypes = filetypes, /* */
170 .filetypes_num = NUM_OF(filetypes), /* */
171 .file_description_prog = file_description_prog, /* */
172 .headers = headers, /* */
173 .headers_num = NUM_OF(headers), /* */
174 .challenges = challenges, /* */
175 .challenges_num = NUM_OF(challenges), /* */
176 .wordfilter_inputs = wordfilter_inputs, /* */
177 .wordfilter_inputs_num = NUM_OF(wordfilter_inputs), /* */
178 .forbidden_inputs = forbidden_inputs, /* */
179 .forbidden_inputs_num = NUM_OF(forbidden_inputs), /* */
182 /* Interpret board */
183 if (!b_arg) {
184 global_ban = 1;
185 } else {
186 board_idx = (size_t) -1;
188 for (size_t j = 0; j < conf.boards_num; ++j) {
189 if (!strcmp(conf.boards[j].name, b_arg)) {
190 board_idx = j;
194 if (board_idx == (size_t) -1) {
195 ERROR_MESSAGE("No board \"%s\" known", b_arg);
196 goto done;
200 /* Interpret IP addresses */
201 if (util_normalize_ip(first_ip, &normalized_first_ip) < 0) {
202 goto done;
205 if (util_normalize_ip(last_ip, &normalized_last_ip) < 0) {
206 goto done;
209 /* Set up a minimal part of the system */
210 if (setup_locks(&conf) < 0) {
211 goto done;
214 if (setup_dbs(&conf) < 0) {
215 goto done;
218 if (setup_write_thread(&conf) < 0) {
219 goto done;
222 ret = db_insert_ban(global_ban, board_idx, normalized_first_ip,
223 normalized_last_ip, ban_message, time(0), until);
224 done:
225 clean_locks();
226 clean_dbs();
227 clean_write_thread();
228 free(normalized_first_ip);
229 free(normalized_last_ip);
231 return ret;