JNIEXPORT void JNICALL Java_eu_faircode_netguard_ServiceSinkhole_jni_1pcap( JNIEnv *env, jclass type, jstring name_, jint record_size, jint file_size) { pcap_record_size = (size_t) record_size; pcap_file_size = file_size; if (pthread_mutex_lock(&lock)) log_android(ANDROID_LOG_ERROR, "pthread_mutex_lock failed"); if (name_ == NULL) { if (pcap_file != NULL) { int flags = fcntl(fileno(pcap_file), F_GETFL, 0); if (flags < 0 || fcntl(fileno(pcap_file), F_SETFL, flags & ~O_NONBLOCK) < 0) log_android(ANDROID_LOG_ERROR, "PCAP fcntl ~O_NONBLOCK error %d: %s", errno, strerror(errno)); if (fsync(fileno(pcap_file))) log_android(ANDROID_LOG_ERROR, "PCAP fsync error %d: %s", errno, strerror(errno)); if (fclose(pcap_file)) log_android(ANDROID_LOG_ERROR, "PCAP fclose error %d: %s", errno, strerror(errno)); pcap_file = NULL; } log_android(ANDROID_LOG_WARN, "PCAP disabled"); } else { const char *name = (*env)->GetStringUTFChars(env, name_, 0); log_android(ANDROID_LOG_WARN, "PCAP file %s record size %d truncate @%ld", name, pcap_record_size, pcap_file_size); pcap_file = fopen(name, "ab+"); if (pcap_file == NULL) log_android(ANDROID_LOG_ERROR, "PCAP fopen error %d: %s", errno, strerror(errno)); else { int flags = fcntl(fileno(pcap_file), F_GETFL, 0); if (flags < 0 || fcntl(fileno(pcap_file), F_SETFL, flags | O_NONBLOCK) < 0) log_android(ANDROID_LOG_ERROR, "PCAP fcntl O_NONBLOCK error %d: %s", errno, strerror(errno)); long size = ftell(pcap_file); if (size == 0) { log_android(ANDROID_LOG_WARN, "PCAP initialize"); write_pcap_hdr(); } else log_android(ANDROID_LOG_WARN, "PCAP current size %ld", size); } (*env)->ReleaseStringUTFChars(env, name_, name); } if (pthread_mutex_unlock(&lock)) log_android(ANDROID_LOG_ERROR, "pthread_mutex_unlock failed"); }
void process_tcp(u_char * data, int skblen) { struct ip *this_iphdr = (struct ip *)data; struct tcphdr *this_tcphdr = (struct tcphdr *)(data + 4 * this_iphdr->ip_hl); int datalen, iplen; int from_client = 1; unsigned int tmp_ts; struct tcp_stream *a_tcp; struct half_stream *snd, *rcv; ugly_iphdr = this_iphdr; iplen = ntohs(this_iphdr->ip_len); if ((unsigned)iplen < 4 * this_iphdr->ip_hl + sizeof(struct tcphdr)) { nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr, this_tcphdr); return; } // ktos sie bawi datalen = iplen - 4 * this_iphdr->ip_hl - 4 * this_tcphdr->th_off; if (datalen < 0) { nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr, this_tcphdr); return; } // ktos sie bawi if ((this_iphdr->ip_src.s_addr | this_iphdr->ip_dst.s_addr) == 0) { nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr, this_tcphdr); return; } if (!(this_tcphdr->th_flags & TH_ACK)) detect_scan(this_iphdr); if (!nids_params.n_tcp_streams) return; /*FIXME: remove the tcp header check function tempor..*/ #ifdef OSPLIT #ifdef CHECK_TCPHDR_DISABLED #if 0 if (my_tcp_check(this_tcphdr, iplen - 4 * this_iphdr->ip_hl, this_iphdr->ip_src.s_addr, this_iphdr->ip_dst.s_addr)) { nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr, this_tcphdr); return; } #endif #else if (my_tcp_check(this_tcphdr, iplen - 4 * this_iphdr->ip_hl, this_iphdr->ip_src.s_addr, this_iphdr->ip_dst.s_addr)) { nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr, this_tcphdr); return; } #endif #endif #if 0 check_flags(this_iphdr, this_tcphdr); //ECN #endif if (!(a_tcp = find_stream(this_tcphdr, this_iphdr, &from_client))) { if ((this_tcphdr->th_flags & TH_SYN) && !(this_tcphdr->th_flags & TH_ACK) && !(this_tcphdr->th_flags & TH_RST)) add_new_tcp(this_tcphdr, this_iphdr); return; } #ifdef OSPLIT struct ipfrag *frag_tag=this_fragments; struct ipfrag *ip_frag_next; if(this_fragments) ip_frag_next=this_fragments->next; /*write all fragment(s) to fp trace file*/ if(is_frag==0) { write_pcap_hdr(a_tcp->fp,(char*)nids_last_pcap_header,sizeof(struct pcap_sf_pkthdr)); write_ip(a_tcp->fp,(char*)this_iphdr,ntohs(this_iphdr->ip_len),(char*)nids_last_pcap_header); } else { /*fragments*/ while(frag_tag!=NULL) { write_pcap_hdr(a_tcp->fp,(char*)(&(frag_tag->pcap_header)),sizeof(struct pcap_sf_pkthdr)); write_ip(a_tcp->fp,(char*)frag_tag->skb->data,frag_tag->wtrace_len,(char*)(&(frag_tag->pcap_header))); free(frag_tag); frag_tag=ip_frag_next; if(ip_frag_next!=NULL) ip_frag_next=ip_frag_next->next; } is_frag=0; } /*set statistic info*/ store_flag=1; #endif if (from_client) { snd = &a_tcp->client; rcv = &a_tcp->server; } else { rcv = &a_tcp->client; snd = &a_tcp->server; } if ((this_tcphdr->th_flags & TH_SYN)) { if (from_client || a_tcp->client.state != TCP_SYN_SENT || a_tcp->server.state != TCP_CLOSE || !(this_tcphdr->th_flags & TH_ACK)) return; if (a_tcp->client.seq != ntohl(this_tcphdr->th_ack)) return; a_tcp->server.state = TCP_SYN_RECV; a_tcp->server.seq = ntohl(this_tcphdr->th_seq) + 1; a_tcp->server.first_data_seq = a_tcp->server.seq; a_tcp->server.ack_seq = ntohl(this_tcphdr->th_ack); a_tcp->server.window = ntohs(this_tcphdr->th_win); if (a_tcp->client.ts_on) { a_tcp->server.ts_on = get_ts(this_tcphdr, &a_tcp->server.curr_ts); if (!a_tcp->server.ts_on) a_tcp->client.ts_on = 0; } else a_tcp->server.ts_on = 0; if (a_tcp->client.wscale_on) { a_tcp->server.wscale_on = get_wscale(this_tcphdr, &a_tcp->server.wscale); if (!a_tcp->server.wscale_on) { a_tcp->client.wscale_on = 0; a_tcp->client.wscale = 1; a_tcp->server.wscale = 1; } } else { a_tcp->server.wscale_on = 0; a_tcp->server.wscale = 1; } return; } if ( ! ( !datalen && ntohl(this_tcphdr->th_seq) == rcv->ack_seq ) && ( !before(ntohl(this_tcphdr->th_seq), rcv->ack_seq + rcv->window*rcv->wscale) || before(ntohl(this_tcphdr->th_seq) + datalen, rcv->ack_seq) ) ) return; if ((this_tcphdr->th_flags & TH_RST)) { if (a_tcp->nids_state == NIDS_DATA) { struct lurker_node *i; a_tcp->nids_state = NIDS_RESET; for (i = a_tcp->listeners; i; i = i->next) (i->item) (a_tcp, &i->data); } nids_free_tcp_stream(a_tcp); return; } /* PAWS check */ if (rcv->ts_on && get_ts(this_tcphdr, &tmp_ts) && before(tmp_ts, snd->curr_ts)) return; if ((this_tcphdr->th_flags & TH_ACK)) { if (from_client && a_tcp->client.state == TCP_SYN_SENT && a_tcp->server.state == TCP_SYN_RECV) { if (ntohl(this_tcphdr->th_ack) == a_tcp->server.seq) { a_tcp->client.state = TCP_ESTABLISHED; a_tcp->client.ack_seq = ntohl(this_tcphdr->th_ack); { struct proc_node *i; struct lurker_node *j; void *data; a_tcp->server.state = TCP_ESTABLISHED; a_tcp->nids_state = NIDS_JUST_EST; for (i = tcp_procs; i; i = i->next) { char whatto = 0; char cc = a_tcp->client.collect; char sc = a_tcp->server.collect; char ccu = a_tcp->client.collect_urg; char scu = a_tcp->server.collect_urg; (i->item) (a_tcp, &data); if (cc < a_tcp->client.collect) whatto |= COLLECT_cc; if (ccu < a_tcp->client.collect_urg) whatto |= COLLECT_ccu; if (sc < a_tcp->server.collect) whatto |= COLLECT_sc; if (scu < a_tcp->server.collect_urg) whatto |= COLLECT_scu; if (nids_params.one_loop_less) { if (a_tcp->client.collect >=2) { a_tcp->client.collect=cc; whatto&=~COLLECT_cc; } if (a_tcp->server.collect >=2 ) { a_tcp->server.collect=sc; whatto&=~COLLECT_sc; } } if (whatto) { j = mknew(struct lurker_node); j->item = i->item; j->data = data; j->whatto = whatto; j->next = a_tcp->listeners; a_tcp->listeners = j; } } #ifdef OSPLIT #if 0 if (!a_tcp->listeners) { nids_free_tcp_stream(a_tcp); return; } #endif #endif a_tcp->nids_state = NIDS_DATA; } } // return; } }
static void add_new_tcp(struct tcphdr * this_tcphdr, struct ip * this_iphdr) { struct tcp_stream *tolink; struct tcp_stream *a_tcp; int hash_index; struct tuple4 addr; addr.source = ntohs(this_tcphdr->th_sport); addr.dest = ntohs(this_tcphdr->th_dport); addr.saddr = this_iphdr->ip_src.s_addr; addr.daddr = this_iphdr->ip_dst.s_addr; hash_index = mk_hash_index(addr); if (tcp_num > max_stream) { struct lurker_node *i; int orig_client_state=tcp_oldest->client.state; tcp_oldest->nids_state = NIDS_TIMED_OUT; for (i = tcp_oldest->listeners; i; i = i->next) (i->item) (tcp_oldest, &i->data); nids_free_tcp_stream(tcp_oldest); if (orig_client_state!=TCP_SYN_SENT) nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_TOOMUCH, ugly_iphdr, this_tcphdr); } a_tcp = free_streams; if (!a_tcp) { fprintf(stderr, "gdb me ...\n"); pause(); } free_streams = a_tcp->next_free; tcp_num++; tolink = tcp_stream_table[hash_index]; memset(a_tcp, 0, sizeof(struct tcp_stream)); #ifdef OSPLIT struct ipfrag *frag_tag=this_fragments; struct ipfrag *ip_frag_next; if(this_fragments) ip_frag_next=this_fragments->next; a_tcp->fp=split_file[(TCP_file_idx++)%SPLIT_FILE_NUM]; /*write all fragment(s) to fp trace file*/ if(is_frag==0) { write_pcap_hdr(a_tcp->fp,(char*)nids_last_pcap_header,sizeof(struct pcap_sf_pkthdr)); write_ip(a_tcp->fp,(char*)this_iphdr,ntohs(this_iphdr->ip_len),(char*)nids_last_pcap_header); } else { /*fragments*/ while(frag_tag!=NULL) { write_pcap_hdr(a_tcp->fp,(char*)(&(frag_tag->pcap_header)),sizeof(struct pcap_sf_pkthdr)); write_ip(a_tcp->fp,(char*)frag_tag->skb->data,frag_tag->wtrace_len,(char*)(&(frag_tag->pcap_header))); free(frag_tag); frag_tag=ip_frag_next; if(ip_frag_next!=NULL) ip_frag_next=ip_frag_next->next; } is_frag=0; } /*set statistic info*/ store_flag=1; #endif a_tcp->hash_index = hash_index; a_tcp->addr = addr; a_tcp->client.state = TCP_SYN_SENT; a_tcp->client.seq = ntohl(this_tcphdr->th_seq) + 1; a_tcp->client.first_data_seq = a_tcp->client.seq; a_tcp->client.window = ntohs(this_tcphdr->th_win); a_tcp->client.ts_on = get_ts(this_tcphdr, &a_tcp->client.curr_ts); a_tcp->client.wscale_on = get_wscale(this_tcphdr, &a_tcp->client.wscale); a_tcp->server.state = TCP_CLOSE; a_tcp->next_node = tolink; a_tcp->prev_node = 0; if (tolink) tolink->prev_node = a_tcp; tcp_stream_table[hash_index] = a_tcp; a_tcp->next_time = tcp_latest; a_tcp->prev_time = 0; if (!tcp_oldest) tcp_oldest = a_tcp; if (tcp_latest) tcp_latest->prev_time = a_tcp; tcp_latest = a_tcp; }
static void write_pcap_hdr(FILE *file) { struct pcap_file_header hdr = { .magic = PCAP_FILE_MAGIC, .version_major = 2, .version_minor = 4, .thiszone = 0, .sigfigs = 0, .snaplen = MAX_PSDU, .linktype = DLT_IEEE802_15_4 }; if (fwrite(&hdr, sizeof(hdr), 1, file) != 1) { perror("fwrite"); exit(1); } } static void write_pcap_rec(FILE *file, const struct timeval *tv, const void *buf, int n) { struct pcap_pkthdr hdr = { .ts_sec = tv->tv_sec, .ts_usec = tv->tv_usec, .caplen = n, .len = n }; if (fwrite(&hdr, sizeof(hdr), 1, file) != 1) { perror("fwrite"); exit(1); } if (fwrite(buf, n, 1, file) != 1) { perror("fwrite"); exit(1); } } static void receive_pcap(struct atrf_dsc *dsc, const char *name) { FILE *file; uint8_t buf[MAX_PSDU+1]; /* PSDU+LQI */ struct timeval now; int n; int count = 0; file = fopen(name, "w"); if (!file) { perror(name); exit(1); } write_pcap_hdr(file); while (run) { wait_for_interrupt(dsc, IRQ_TRX_END, quick ? 0xff : IRQ_TRX_END | IRQ_RX_START | IRQ_AMI, quick ? -1 : 0); if (!run) break; gettimeofday(&now, NULL); n = atrf_buf_read(dsc, buf, sizeof(buf)); if (n < 0) exit(1); if (n < 2) { fprintf(stderr, "%d bytes received\n", n); continue; } write_pcap_rec(file, &now, buf, n-1); if (!quick) (void) write(2, ".", 1); count++; } if (fclose(file) == EOF) { perror(name); exit(1); } fprintf(stderr, "%sreceived %d message%s\n", count ? "\n" : "", count, count == 1 ? "" : "s"); } static void receive(struct atrf_dsc *dsc, const char *name, int hex) { atrf_reg_write(dsc, REG_TRX_STATE, TRX_CMD_RX_ON); /* * 180 us, according to AVR2001 section 4.2. We time out after * nominally 200 us. */ wait_for_interrupt(dsc, IRQ_PLL_LOCK, IRQ_PLL_LOCK, 1); if (name) receive_pcap(dsc, name); else receive_message(dsc, hex); }