static void heartbeat(int fd, short evtype, void *arg) { static struct timeval now, diff, tv = {0, 0}; struct mg *mg = arg; /* garbage collector - free whenever garbage > 128KB */ if (mmatic_size(mg->mmtmp) > 1024 * 128) { mmatic_free(mg->mmtmp); mg->mmtmp = mmatic_create(); } /* if no line generator is running and there was no packet to us in last 60 seconds - exit */ if (mg->running == 0) { gettimeofday(&now, NULL); timersub(&now, &mg->last, &diff); if (diff.tv_sec >= 60) { dbg(0, "Finished, exiting...\n"); mg->running--; event_base_loopexit(mg->evb, &tv); return; } } mgs_uschedule(&mg->hbs, HEARTBEAT_PERIOD); }
void flow(struct lfc *lfc, void *pdata, struct lfc_flow *lf, void *data) { struct flow *f = data; printf(",%s", p2s[f->proto]); mmatic_free(f->ipq_flow); }
void pcap_deinit(struct tracedump *td) { /* close the reader and wait for it */ pthread_cancel(td->pc->reader); pthread_join(td->pc->reader, NULL); close(td->pc->fd); fclose(td->pc->fp); /* free the memory */ mmatic_free(td->pc); }
void pcap_update(struct tracedump *td) { struct sock_fprog *fp; pthread_mutex_lock(&td->mutex_ports); /* generate BPF filter code basing on the current port list */ fp = gencode_alloc(td); #ifdef CHECK_BPF /* verify the code on the user side - useful for debugging */ sk_chk_filter(fp->filter, fp->len); #endif /* attach the filter */ if (setsockopt(td->pc->fd, SOL_SOCKET, SO_ATTACH_FILTER, fp, sizeof *fp) != 0) die_errno("setsockopt"); pthread_mutex_unlock(&td->mutex_ports); mmatic_free(fp->filter); mmatic_free(fp); }
int32_t inject_socketcall(struct tracedump *td, struct pid *sp, uint32_t sc_code, ...) { /* int 0x80, int3 */ unsigned char code[4] = { 0xcd, 0x80, 0xcc, 0 }; char backup[4]; struct user_regs_struct regs, regs2; int ss_vals, ss_mem, ss; va_list vl; enum arg_type type; uint32_t sv; void *ptr; uint8_t *stack, *stack_mem; uint32_t *stack32; int i, j; /* * get the required amount of stack space */ ss_vals = 0; ss_mem = 0; va_start(vl, sc_code); do { type = va_arg(vl, enum arg_type); if (type == AT_LAST) break; sv = va_arg(vl, uint32_t); /* each socketcall argument takes 4 bytes */ ss_vals += 4; /* if its memory, it takes additional sv bytes */ if (type == AT_MEM_IN || type == AT_MEM_INOUT) { ss_mem += sv; ptr = va_arg(vl, void *); } } while (true); va_end(vl); ss = ss_vals + ss_mem; /* * backup */ ptrace_getregs(sp, ®s); memcpy(®s2, ®s, sizeof regs); ptrace_read(sp, regs.eip, backup, sizeof backup); /* * write the stack */ stack = mmatic_zalloc(td->mm, ss); stack32 = (uint32_t *) stack; stack_mem = stack + ss_vals; va_start(vl, sc_code); i = 0; j = 0; do { type = va_arg(vl, enum arg_type); if (type == AT_LAST) break; sv = va_arg(vl, uint32_t); if (type == AT_VALUE) { stack32[i++] = sv; } else { /* i.e. its a memory arg */ stack32[i++] = regs.esp - ss_mem + j; /* copy the memory */ ptr = va_arg(vl, void *); memcpy(stack_mem + j, ptr, sv); j += sv; } } while (true); va_end(vl); ptrace_write(sp, regs.esp - ss, stack, ss); /* * write the code and run */ regs2.eax = 102; // socketcall regs2.ebx = sc_code; regs2.ecx = regs.esp - ss; ptrace_write(sp, regs.eip, code, sizeof code); ptrace_setregs(sp, ®s2); ptrace_cont(sp, 0, true); /* * read back */ ptrace_getregs(sp, ®s2); ptrace_read(sp, regs.esp - ss_mem, stack_mem, ss_mem); va_start(vl, sc_code); do { type = va_arg(vl, enum arg_type); if (type == AT_LAST) break; sv = va_arg(vl, uint32_t); if (type == AT_VALUE) continue; ptr = va_arg(vl, void *); if (type == AT_MEM_IN) continue; memcpy(ptr, stack_mem, sv); stack_mem += sv; } while (true); va_end(vl); /* restore */ ptrace_write(sp, regs.eip, backup, sizeof backup); ptrace_setregs(sp, ®s); mmatic_free(stack); return regs2.eax; }
int main(int argc, char *argv[]) { mmatic *mm = mmatic_create(); mmatic *mmtmp = mmatic_create(); struct mg *mg; int i; /* * initialize and parse config */ mg = mmatic_zalloc(mm, sizeof(struct mg)); mg->mm = mm; mg->mmtmp = mmtmp; apply_defaults(mg); /* get my id number from hostname */ fetch_myid(mg); /* parse command line options */ if (parse_argv(mg, argc, argv)) return 1; /* parse configuration file options */ if (mg->options.conf_file) { if (parse_config(mg)) return 4; } /* * config syntax looks OK, see if it is feasible */ /* initialize random number generator */ srand48(mg->options.myid); /* init libevent */ mg->evb = event_init(); event_set_log_callback(libevent_log); /* init stats structures so mgstats_aggregator_add() used somewhere below works */ mgstats_init(mg); /* attach to raw interfaces */ if (mgi_init(mg, handle_packet) <= 0) { dbg(0, "no available interfaces found\n"); return 2; } /* parse traffic file */ if (parse_traffic(mg)) return 3; /* * all OK, prepare to start */ /* synchronize time reference point on all nodes */ mgc_sync(mg); /* schedule stats writing */ mgstats_start(mg); /* attach global stats */ _stats_init(mg); /* schedule heartbeat and disk sync signals */ heartbeat_init(mg); sync_init(mg); /* schedule the real work of this node: line generators */ for (i = 1; i < TRAFFIC_LINE_MAX; i++) { if (!(mg->lines[i] && mg->lines[i]->my)) continue; /* this will schedule first execution */ mgs_sleep(mg->lines[i], NULL); mg->running++; } /* suppose last frame was received now */ gettimeofday(&mg->last, NULL); /* * start! */ dbg(0, "Starting\n"); event_base_dispatch(mg->evb); /*******************************/ /* * cleanup after end of libevent loop */ event_base_free(mg->evb); mmatic_free(mg->mm); mmatic_free(mg->mmtmp); fflush(NULL); sync(); return 0; }
int32_t inject_socketcall(struct tracedump *td, struct pid *sp, uint32_t sc_code, ...) { struct user_regs_struct regs, regs2; int ss_vals, ss_mem, ss; va_list vl; enum arg_type type; uint32_t sv; void *ptr; uint8_t *stack, *stack_mem; uint32_t *stack32; int i, j; /* * get the required amount of stack space */ ss_vals = 0; // stack space for immediate values ss_mem = 0; // stack space for pointer values va_start(vl, sc_code); do { type = va_arg(vl, enum arg_type); if (type == AT_LAST) break; sv = va_arg(vl, uint32_t); /* each socketcall argument takes 4 bytes */ ss_vals += 4; /* if its memory, it takes additional sv bytes */ if (type == AT_MEM_IN || type == AT_MEM_INOUT) { ss_mem += sv; ptr = va_arg(vl, void *); } } while (true); va_end(vl); ss = ss_vals + ss_mem; /* * backup */ ptrace_getregs(sp, ®s); memcpy(®s2, ®s, sizeof regs); /* * write the stack */ stack = mmatic_zalloc(td->mm, ss); // stack area for immediate values stack32 = (uint32_t *) stack; stack_mem = stack + ss_vals; // stack area for pointer values va_start(vl, sc_code); i = 0; j = 0; do { type = va_arg(vl, enum arg_type); if (type == AT_LAST) break; sv = va_arg(vl, uint32_t); if (type == AT_VALUE) { stack32[i++] = sv; } else { /* i.e. its a memory arg */ stack32[i++] = regs.esp - ss_mem + j; /* copy the memory */ ptr = va_arg(vl, void *); memcpy(stack_mem + j, ptr, sv); j += sv; } } while (true); va_end(vl); ptrace_write(sp, regs.esp - ss, stack, ss); /* * write the code and run */ _prepare(sp); regs2.eax = 102; // socketcall regs2.ebx = sc_code; regs2.ecx = regs.esp - ss; regs2.eip = sp->vdso_addr; // gateway to int3 ptrace_setregs(sp, ®s2); ptrace_cont_syscall(sp, 0, true); // enter... ptrace_cont_syscall(sp, 0, true); // ...and exit /* * read back */ ptrace_getregs(sp, ®s2); ptrace_read(sp, regs.esp - ss_mem, stack_mem, ss_mem); va_start(vl, sc_code); do { type = va_arg(vl, enum arg_type); if (type == AT_LAST) break; sv = va_arg(vl, uint32_t); if (type == AT_VALUE) continue; ptr = va_arg(vl, void *); if (type == AT_MEM_IN) continue; memcpy(ptr, stack_mem, sv); stack_mem += sv; } while (true); va_end(vl); /* restore */ ptrace_setregs(sp, ®s); mmatic_free(stack); return regs2.eax; }
static void *gc_thread(void *arg) { struct tracedump *td; sigset_t ss; uint8_t *tcp = NULL, *udp = NULL; unsigned int port; struct port *sp; int count = 0; struct timeval now; td = (struct tracedump *) arg; sigaddset(&ss, SIGTERM); sigaddset(&ss, SIGINT); pthread_sigmask(SIG_SETMASK, &ss, NULL); while (1) { sleep(60); /* read list of active tcp/udp ports */ tcp = port_list(td, true); udp = port_list(td, false); if (!tcp || !udp) { dbg(1, "gc: reading tcp/udp ports failed\n"); goto next; } /* * iterate through all monitored TCP/UDP ports and delete those * that are not needed anymore */ pthread_mutex_lock(&td->mutex_ports); gettimeofday(&now, NULL); /* TCP */ thash_reset(td->tcp_ports); while ((sp = thash_uint_iter(td->tcp_ports, &port))) { /* skip ports "younger" than 60 secs * workaround that autobound TCP ports are not visible in procfs - Linux bug? */ if (pjf_timediff(&now, &sp->since)/1000000 < 60) continue; if (!PORT_ISSET(tcp, port)) { count++; thash_uint_set(td->tcp_ports, port, NULL); dbg(3, "port TCP/%d deleted\n", port); } } /* UDP */ thash_reset(td->udp_ports); while ((sp = thash_uint_iter(td->udp_ports, &port))) { if (!PORT_ISSET(udp, port)) { count++; thash_uint_set(td->udp_ports, port, NULL); dbg(3, "port UDP/%d deleted\n", port); } } pthread_mutex_unlock(&td->mutex_ports); /* if any changes were made, run the BPF filter update */ if (count > 0) pcap_update(td); next: if (tcp) mmatic_free(tcp); if (udp) mmatic_free(udp); } return NULL; }
void verdict_free(struct spi *spi) { mmatic_free(spi->vdata); return; }
void flow_destroy(struct spi_flow *flow) { mmatic_free(flow); }