00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <dlfcn.h>
00036 #include <errno.h>
00037 #include <unistd.h>
00038 #include <sys/mman.h>
00039 #include <sys/wait.h>
00040 #include <time.h>
00041 #include <assert.h>
00042
00043 #define EUREPHIA_FWINTF
00044 #include <eurephiafw_struct.h>
00045 #include <eurephia_context.h>
00046 #include "eurephia_log.h"
00047 #include "eurephiafw.h"
00048 #include "eurephiafw_intf.h"
00049 #include "eurephia_getsym.h"
00050 #include "eurephia_nullsafe.h"
00051 #include "eurephia_values.h"
00052 #include "eurephiafw_helpers.h"
00053 #include "eurephiadb_driver.h"
00054
00055
00063 int eFW_unload(eurephiaCTX *ctx) {
00064 if( ctx == NULL ) {
00065 return 1;
00066 }
00067
00068 if( ctx->eurephia_fw_intf != NULL ) {
00069 eurephia_log(ctx, LOG_INFO, 3, "Unloading eurephia firewall interface");
00070 dlclose(ctx->eurephia_fw_intf);
00071 ctx->eurephia_fw_intf = NULL;
00072 return 0;
00073 }
00074 return 1;
00075 }
00076
00077
00086 int eFW_load(eurephiaCTX *ctx, const char *intf) {
00087 if( (intf == NULL) || (strlen(intf) == 0) ) {
00088 eurephia_log(ctx, LOG_FATAL, 0, "No valid eurephia firewall interface indicated");
00089 return 0;
00090 }
00091 eurephia_log(ctx, LOG_INFO, 2, "Loading eurephia firewall interface: %s", intf);
00092
00093 ctx->eurephia_fw_intf = dlopen(intf, RTLD_NOW);
00094 if( ctx->eurephia_fw_intf == NULL ) {
00095 eurephia_log(ctx, LOG_FATAL, 0, "Could not open the eurephia firewall interface (%s)", intf);
00096 eurephia_log(ctx, LOG_FATAL, 1, "dlopen error: %s", dlerror());
00097 return 0;
00098 }
00099
00100
00101 eFWinterfaceVersion = eGetSym(ctx, ctx->eurephia_fw_intf, "eFWinterfaceVersion");
00102 eFWinterfaceAPIversion = eGetSym(ctx, ctx->eurephia_fw_intf, "eFWinterfaceAPIversion");
00103
00104 eurephia_log(ctx, LOG_INFO, 1, "Firewall interface loaded: %s (API version %i)",
00105 eFWinterfaceVersion(), eFWinterfaceAPIversion());
00106
00107
00108 switch( eFWinterfaceAPIversion() ) {
00109 default:
00110 eurephia_log(ctx, LOG_WARNING, 0,
00111 "eurephia Firewall interface API is newer than what the running eurephia version is "
00112 "familiar with. Please consider to upgrade eurephia to take advantage of newer "
00113 "features in the eurephiaDB driver.");
00114
00115 case 1:
00116 eFW_RunFirewall = eGetSym(ctx, ctx->eurephia_fw_intf, "eFW_RunFirewall");
00117 break;
00118
00119 }
00120
00121 if( ctx->fatal_error > 0 ) {
00122 eurephia_log(ctx, LOG_FATAL, 0, "eurephia Firewall interface is not correctly initialised. "
00123 "eurephia authentication will not be available");
00124 eFW_unload(ctx);
00125 return 0;
00126 }
00127 return 1;
00128 }
00129
00130
00137 void eFW_StartFirewall(eurephiaCTX *ctx) {
00138 struct mq_attr mqattr;
00139 eurephiaCTX *shadowctx = NULL;
00140 char buf[1026], *fwdest = NULL;
00141 unsigned int prio;
00142
00143 ctx->fwcfg = (eurephiaFWINTF *) malloc_nullsafe(ctx, sizeof(eurephiaFWINTF)+2);
00144
00145
00146 shadowctx = (eurephiaCTX *) malloc_nullsafe(ctx, sizeof(eurephiaCTX)+2);
00147 assert( shadowctx != NULL );
00148 if( mlock(shadowctx, sizeof(eurephiaCTX)+2) < 0 ) {
00149 eurephia_log(ctx, LOG_CRITICAL, 0, "Could not mlock() firewall context: %s",
00150 strerror(errno));
00151 };
00152 shadowctx->context_type = ECTX_NO_PRIVILEGES;
00153 shadowctx->log = ctx->log;
00154 (*ctx->fwcfg).thrdata.ctx = shadowctx;
00155
00156 (*ctx->fwcfg).thrdata.fw_command = strdup_nullsafe(eGet_value(ctx->dbc->config, "firewall_command"));
00157 if( (*ctx->fwcfg).thrdata.fw_command == NULL) {
00158 eurephia_log(ctx, LOG_PANIC, 0, "Could not find firewall_command in configuration. "
00159 "Firewall updates will not be available.");
00160 return;
00161 } else {
00162 eurephia_log(ctx, LOG_INFO, 1, "Using %s to update the firewall rules.",
00163 (*ctx->fwcfg).thrdata.fw_command );
00164 }
00165
00166 fwdest = eGet_value(ctx->dbc->config, "firewall_destination");
00167 if( fwdest == NULL ) {
00168 eurephia_log(ctx, LOG_PANIC, 0, "Could not find firewall_destination in configuration. "
00169 "Firewall updates will not be available.");
00170 return;
00171 } else {
00172 eurephia_log(ctx, LOG_INFO, 1, "Using '%s' as firewall rule for VPN accesses", fwdest);
00173 }
00174
00175 ctx->fwcfg->fwblacklist = eGet_value(ctx->dbc->config, "firewall_blacklist_destination");
00176 if( ctx->fwcfg->fwblacklist != NULL ) {
00177 eurephia_log(ctx, LOG_INFO, 1,
00178 "Blacklisted IP addresses will also be blocked in '%s'",
00179 ctx->fwcfg->fwblacklist);
00180
00181
00182 ctx->fwcfg->blacklisted = eCreate_value_space(ctx, 20);
00183
00184
00185 ctx->fwcfg->fwblacklist_sendto = eGet_value(ctx->dbc->config, "firewall_blacklist_send_to");
00186 if( ctx->fwcfg->fwblacklist_sendto == NULL ) {
00187 ctx->fwcfg->fwblacklist_sendto = strdup("DROP\0");
00188 eurephia_log(ctx, LOG_INFO, 2,"Blacklisted IP addresses will be dropped immediately");
00189 } else {
00190 eurephia_log(ctx, LOG_INFO, 2,"Blacklisted IP addresses will be sent to '%s'",
00191 ctx->fwcfg->fwblacklist_sendto);
00192 }
00193 }
00194
00195 eurephia_log(ctx, LOG_INFO, 3, "Starting eurephia firewall interface");
00196
00197
00198 if( efwSetupSemaphores(ctx, &(*ctx->fwcfg).thrdata) == 0 ) {
00199 free_nullsafe(ctx, ctx->fwcfg->thrdata.fw_command);
00200 return;
00201 };
00202
00203
00204 if( efwSetupMessageQueue(ctx, &(*ctx->fwcfg).thrdata) == 0 ) {
00205 free_nullsafe(ctx, ctx->fwcfg);
00206 return;
00207 }
00208
00209
00210 madvise(ctx, sizeof(eurephiaCTX), MADV_DONTFORK);
00211
00212
00213 if( (ctx->fwcfg->fwproc_pid = fork()) < 0 ) {
00214 eurephia_log(ctx, LOG_PANIC, 0,
00215 "Could not fork out a child process for the firewall interface (%s)",
00216 strerror(errno));
00217 return;
00218 }
00219 switch( ctx->fwcfg->fwproc_pid ) {
00220 case 0:
00221 eDBdisconnect(ctx);
00222 eFW_RunFirewall(&(*ctx->fwcfg).thrdata);
00223 exit(-1);
00224
00225 default:
00226 eurephia_log(ctx, LOG_INFO, 2, "Firewall updater process started (pid %i)",
00227 ctx->fwcfg->fwproc_pid);
00228 }
00229
00230
00231 if( mq_getattr((*ctx->fwcfg).thrdata.msgq, &mqattr) == 0 ) {
00232 long i;
00233
00234 memset(&buf, 0, 1026);
00235 if( mqattr.mq_curmsgs > 0 ) {
00236 for( i = 0; i < mqattr.mq_curmsgs; i++ ) {
00237 if( mq_receive((*ctx->fwcfg).thrdata.msgq, &buf[0], 1024, &prio) == -1 ) {
00238 eurephia_log(ctx, LOG_CRITICAL, 0,
00239 "Error while emptying messages from queue: %s",
00240 strerror(errno));
00241 } else {
00242 DEBUG(ctx, 28, "Removed message on queue: %s", buf);
00243 }
00244 }
00245 }
00246 eurephia_log(ctx, LOG_INFO, 3, "Message queue for firewall updates is ready");
00247 } else {
00248 eurephia_log(ctx, LOG_FATAL, 0, "Could not retrieve message queue attributes (%s)",
00249 strerror(errno));
00250 }
00251
00252
00253 sem_post(ctx->fwcfg->thrdata.semp_master);
00254
00255
00256 DEBUG(ctx, 28, "eFW master is ready, waiting for the eFW worker to get ready");
00257 sem_wait(ctx->fwcfg->thrdata.semp_worker);
00258 eurephia_log(ctx, LOG_INFO, 2, "eFW interface initialised.");
00259
00260
00261 memset(&buf, 0, 1026);
00262 snprintf(buf, 1024, "I %s", fwdest);
00263 if( mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1) == -1 ) {
00264 eurephia_log(ctx, LOG_ERROR, 0, "Could not request firewall initialisation of the %s chain: %s",
00265 fwdest, strerror(errno));
00266 };
00267
00268 if( ctx->fwcfg->fwblacklist != NULL ) {
00269 eurephiaVALUES *blacklisted = NULL, *p = NULL;
00270
00271 snprintf(buf, 1024, "F %s", ctx->fwcfg->fwblacklist);
00272 if( mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1) == -1 ) {
00273 eurephia_log(ctx, LOG_ERROR, 0, "Could not request flushing of the %s chain: %s",
00274 ctx->fwcfg->fwblacklist, strerror(errno));
00275 };
00276
00277
00278 blacklisted = eDBget_blacklisted_ip(ctx);
00279 p = blacklisted;
00280 while( p != NULL ) {
00281 if( p->val != NULL ) {
00282 eFW_UpdateFirewall(ctx, FWRULE_BLACKLIST, p->val, ctx->fwcfg->fwblacklist, NULL);
00283 }
00284 p = p->next;
00285 }
00286 eFree_values(ctx, blacklisted);
00287 }
00288 }
00289
00290
00296 void eFW_StopFirewall(eurephiaCTX *ctx) {
00297 char buf[520], *fwdest = NULL;
00298 struct timespec tsp;
00299
00300 if( ctx->fwcfg == NULL ) {
00301 return;
00302 }
00303
00304 eurephia_log(ctx, LOG_INFO, 2, "Stopping eurephia firewall interface");
00305
00306
00307
00308 fwdest = eGet_value(ctx->dbc->config, "firewall_destination");
00309 if( fwdest != NULL ) {
00310 memset(&buf, 0, 520);
00311 snprintf(buf, 512, "F %s", fwdest);
00312 if( mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1) == -1 ) {
00313 eurephia_log(ctx, LOG_CRITICAL, 0,
00314 "Could not request firewall flushing of the %s chain: %s",
00315 fwdest, strerror(errno));
00316 };
00317 } else {
00318 eurephia_log(ctx, LOG_CRITICAL, 0, "firewall_destination not set in config. Will not flush "
00319 "firewall before shutting down the firewall interface.");
00320 }
00321
00322
00323
00324 memset(&buf, 0, 520);
00325 snprintf(buf, 512, "FWSHUTDOWN%c", 0);
00326 if( mq_send((*ctx->fwcfg).thrdata.msgq, buf, 11, 1) == -1 ) {
00327 eurephia_log(ctx, LOG_PANIC, 0, "Could not initiate shutdown on eFW module: %s", strerror(errno));
00328 kill(ctx->fwcfg->fwproc_pid, SIGABRT);
00329 }
00330
00331
00332
00333
00334
00335
00336 if( clock_gettime(CLOCK_REALTIME, &tsp) == -1 ) {
00337 eurephia_log(ctx, LOG_FATAL, 0, "Could not prepare timeout for firewall shutdown: %s",
00338 strerror(errno));
00339 sleep(3);
00340 kill(ctx->fwcfg->fwproc_pid, SIGABRT);
00341 }
00342 tsp.tv_sec += 30;
00343
00344
00345 if( sem_timedwait(ctx->fwcfg->thrdata.semp_worker, &tsp) == -1 ) {
00346 eurephia_log(ctx, LOG_PANIC, 0, "Failed to wait for eFW module process to quit: %s",
00347 strerror(errno));
00348 sleep(3);
00349 kill(ctx->fwcfg->fwproc_pid, SIGABRT);
00350 }
00351
00352
00353 sem_post(ctx->fwcfg->thrdata.semp_master);
00354
00355
00356 munlock(ctx->fwcfg->thrdata.ctx, sizeof(eurephiaCTX)+2);
00357 free_nullsafe(ctx, ctx->fwcfg->thrdata.ctx);
00358 free_nullsafe(ctx, ctx->fwcfg->fwblacklist_sendto);
00359 eFree_values(ctx, ctx->fwcfg->blacklisted);
00360 free_nullsafe(ctx, (*ctx->fwcfg).thrdata.fw_command);
00361 free_nullsafe(ctx, ctx->fwcfg);
00362 eurephia_log(ctx, LOG_INFO, 2, "eurephia firewall interface is stopped");
00363 }
00364
00365
00377 int eFW_UpdateFirewall(eurephiaCTX *ctx, int mode,
00378 const char *addr, const char *fwdest, const char *fwprofile) {
00379 char buf[1026];
00380 char *blchk = NULL;
00381
00382 if( (*ctx->fwcfg).thrdata.fw_command == NULL ) {
00383 eurephia_log(ctx, LOG_FATAL, 0, "Function call: eFW_UpdateFirewall() -- "
00384 "firewall_command is not configured. Firewall rules was not updated.");
00385 return 0;
00386 }
00387
00388 memset(&buf, 0, 1026);
00389 switch( mode ) {
00390 case FWRULE_ADD:
00391 eurephia_log(ctx, LOG_INFO, 3,
00392 "Function call: eFW_UpdateFirewall(ctx, %s, '%.18s', '%s', '%s')",
00393 "ADD", addr, fwdest, fwprofile);
00394 snprintf(buf, 1024, "A %.18s %s %s", addr, fwdest, fwprofile);
00395 mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1);
00396 return 1;
00397
00398 case FWRULE_DELETE:
00399 eurephia_log(ctx, LOG_INFO, 3,
00400 "Function call: eFW_UpdateFirewall(ctx, %s, '%.18s', '%s', '%s')",
00401 "DELETE", addr, fwdest, fwprofile);
00402 snprintf(buf, 1024, "D %.18s %s %s", addr, fwdest, fwprofile);
00403 mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1);
00404 return 1;
00405
00406 case FWRULE_BLACKLIST:
00407 eurephia_log(ctx, LOG_INFO, 3,
00408 "Function call: eFW_UpdateFirewall(ctx, %s, '%.34s','%s', NULL)",
00409 "BLACKLIST", addr, fwdest);
00410
00411
00412 if( (blchk = eGet_value(ctx->fwcfg->blacklisted, addr)) == NULL ) {
00413 snprintf(buf, 1024, "B %.34s %s %s", addr, fwdest, ctx->fwcfg->fwblacklist_sendto);
00414 mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1);
00415 eAdd_value(ctx, ctx->fwcfg->blacklisted, addr, fwdest);
00416 } else {
00417 eurephia_log(ctx, LOG_INFO, 5, "IP address already blacklisted in '%s'", blchk);
00418 }
00419 return 1;
00420
00421 default:
00422 eurephia_log(ctx, LOG_CRITICAL, 0,
00423 "Function call: eFW_UpdateFirewall(ctx, %s, '%s') - UNKNOWN MODE", "(unknown)",
00424 addr);
00425 return 0;
00426 }
00427 }