int ReCalculateChecksum(Packet *p) { if (PKT_IS_IPV4(p)) { if (PKT_IS_TCP(p)) { /* TCP */ p->tcph->th_sum = 0; p->tcph->th_sum = TCPChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p)), 0); } else if (PKT_IS_UDP(p)) { p->udph->uh_sum = 0; p->udph->uh_sum = UDPV4Checksum(p->ip4h->s_ip_addrs, (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN), 0); } /* IPV4 */ p->ip4h->ip_csum = 0; p->ip4h->ip_csum = IPV4Checksum((uint16_t *)p->ip4h, IPV4_GET_RAW_HLEN(p->ip4h), 0); } else if (PKT_IS_IPV6(p)) { /* just TCP for IPV6 */ if (PKT_IS_TCP(p)) { p->tcph->th_sum = 0; p->tcph->th_sum = TCPV6Checksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, (p->payload_len + TCP_GET_HLEN(p)), 0); } else if (PKT_IS_UDP(p)) { p->udph->uh_sum = 0; p->udph->uh_sum = UDPV6Checksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->udph, (p->payload_len + UDP_HEADER_LEN), 0); } } return 0; }
/** * \brief Recalculate the csum for a modified packet * * \param p packet to inspect */ void StreamTcpInlineRecalcCsum(Packet *p) { if (!(p->flags & PKT_STREAM_MODIFIED)) { SCReturn; } if (!(PKT_IS_TCP(p))) { SCReturn; } if (PKT_IS_IPV4(p)) { /* TCP */ p->tcph->th_sum = 0; p->tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p->ip4h->ip_src), (uint16_t *)p->tcph, (p->payload_len + p->tcpvars.hlen)); /* IPV4 */ p->ip4h->ip_csum = 0; p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, IPV4_GET_RAW_HLEN(p->ip4h)); } else if (PKT_IS_IPV6(p)) { /* just TCP for IPV6 */ p->tcph->th_sum = 0; p->tcph->th_sum = TCPV6CalculateChecksum((uint16_t *)&(p->ip6h->ip6_src), (uint16_t *)p->tcph, (p->payload_len + p->tcpvars.hlen)); } SCReturn; }
/** * \brief Add IPv4 header data, to be stored in the Additional Data * field of the IDMEF alert (see section 4.2.4.6 of RFC 4765). * * \return 0 if ok */ static int PacketToDataV4(Packet *p, PacketAlert *pa, idmef_alert_t *alert) { SCEnter(); AddIntData(alert, "ip_ver", IPV4_GET_RAW_VER(p->ip4h)); AddIntData(alert, "ip_hlen", IPV4_GET_RAW_HLEN(p->ip4h)); AddIntData(alert, "ip_tos", IPV4_GET_RAW_IPTOS(p->ip4h)); AddIntData(alert, "ip_len", ntohs(IPV4_GET_RAW_IPLEN(p->ip4h))); AddIntData(alert, "ip_id", ntohs(IPV4_GET_RAW_IPID(p->ip4h))); AddIntData(alert, "ip_off", ntohs(IPV4_GET_RAW_IPOFFSET(p->ip4h))); AddIntData(alert, "ip_ttl", IPV4_GET_RAW_IPTTL(p->ip4h)); AddIntData(alert, "ip_proto", IPV4_GET_RAW_IPPROTO(p->ip4h)); AddIntData(alert, "ip_sum", ntohs(p->ip4h->ip_csum)); SCReturnInt(0); }
/** * \brief Checks if the packet sent as the argument, has a valid or invalid * icmpv4 checksum, based on whether icmpv4-csum option for this rule * has been supplied with "valid" or "invalid" argument * * \param t Pointer to the tv for this detection module instance * \param det_ctx Pointer to the detection engine thread context * \param p Pointer to the Packet currently being matched * \param s Pointer to the Signature, the packet is being currently * matched with * \param m Pointer to the keyword_structure(SigMatch) from the above * Signature, the Packet is being currently matched with * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ static int DetectICMPV4CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip4h == NULL || p->icmpv4h == NULL || p->proto != IPPROTO_ICMP || PKT_IS_PSEUDOPKT(p)) return 0; if (p->flags & PKT_IGNORE_CHECKSUM) { return cd->valid; } if (p->level4_comp_csum == -1) p->level4_comp_csum = ICMPV4CalculateChecksum((uint16_t *)p->icmpv4h, ntohs(IPV4_GET_RAW_IPLEN(p->ip4h)) - IPV4_GET_RAW_HLEN(p->ip4h) * 4); if (p->level4_comp_csum == p->icmpv4h->checksum && cd->valid == 1) return 1; else if (p->level4_comp_csum != p->icmpv4h->checksum && cd->valid == 0) return 1; else return 0; }
/** * \brief Write a faked Packet in unified2 file for each stream segment. */ static int Unified2PrintStreamSegmentCallback(Packet *p, void *data, uint8_t *buf, uint32_t buflen) { int ret = 1; Unified2AlertThread *aun = (Unified2AlertThread *)data; Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data); Unified2Packet *phdr = (Unified2Packet *)(hdr + 1); int ethh_offset = 0; EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) }; uint32_t hdr_length = 0; int datalink = p->datalink; memset(hdr, 0, sizeof(Unified2AlertFileHeader)); memset(phdr, 0, sizeof(Unified2Packet)); hdr->type = htonl(UNIFIED2_PACKET_TYPE); aun->hdr = hdr; phdr->sensor_id = htonl(sensor_id); phdr->linktype = htonl(datalink); phdr->event_id = aun->event_id; phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec); phdr->packet_microsecond = htonl(p->ts.tv_usec); aun->phdr = phdr; if (p->datalink != DLT_EN10MB) { /* We have raw data here */ phdr->linktype = htonl(DLT_RAW); datalink = DLT_RAW; } aun->length = sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE; aun->offset = sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE; /* Include Packet header */ if (PKT_IS_IPV4(p)) { FakeIPv4Hdr fakehdr; hdr_length = sizeof(FakeIPv4Hdr); if (p->datalink == DLT_EN10MB) { /* Fake this */ ethh_offset = 14; datalink = DLT_EN10MB; phdr->linktype = htonl(datalink); aun->length += ethh_offset; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); goto error; } ethhdr.eth_type = htons(ETHERNET_TYPE_IP); memcpy(aun->data + aun->offset, ðhdr, 14); aun->offset += ethh_offset; } memset(&fakehdr, 0, hdr_length); aun->length += hdr_length; Unified2ForgeFakeIPv4Header(&fakehdr, p, hdr_length + buflen, 0); if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); goto error; } memcpy(aun->data + aun->offset, &fakehdr, hdr_length); aun->iphdr = (void *)(aun->data + aun->offset); aun->offset += hdr_length; } else if (PKT_IS_IPV6(p)) { FakeIPv6Hdr fakehdr; hdr_length = sizeof(FakeIPv6Hdr); if (p->datalink == DLT_EN10MB) { /* Fake this */ ethh_offset = 14; datalink = DLT_EN10MB; phdr->linktype = htonl(datalink); aun->length += ethh_offset; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); goto error; } ethhdr.eth_type = htons(ETHERNET_TYPE_IPV6); memcpy(aun->data + aun->offset, ðhdr, 14); aun->offset += ethh_offset; } memset(&fakehdr, 0, hdr_length); Unified2ForgeFakeIPv6Header(&fakehdr, p, buflen, 1); aun->length += hdr_length; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data"); goto error; } memcpy(aun->data + aun->offset, &fakehdr, hdr_length); aun->iphdr = (void *)(aun->data + aun->offset); aun->offset += hdr_length; } else { goto error; } /* update unified2 headers for length */ aun->hdr->length = htonl(UNIFIED2_PACKET_SIZE + ethh_offset + hdr_length + buflen); aun->phdr->packet_length = htonl(ethh_offset + hdr_length + buflen); /* copy stream segment payload in */ aun->length += buflen; if (aun->length > aun->datalen) { SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread" " data: %d vs %d", aun->length, aun->datalen); goto error; } memcpy(aun->data + aun->offset, buf, buflen); aun->offset += buflen; /* rebuild checksum */ if (PKT_IS_IPV6(p)) { FakeIPv6Hdr *fakehdr = (FakeIPv6Hdr *)aun->iphdr; fakehdr->tcph.th_sum = TCPV6CalculateChecksum(fakehdr->ip6h.s_ip6_addrs, (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr)); } else { FakeIPv4Hdr *fakehdr = (FakeIPv4Hdr *)aun->iphdr; fakehdr->tcph.th_sum = TCPCalculateChecksum(fakehdr->ip4h.s_ip_addrs, (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr)); fakehdr->ip4h.ip_csum = IPV4CalculateChecksum((uint16_t *)&fakehdr->ip4h, IPV4_GET_RAW_HLEN(&fakehdr->ip4h)); } /* write out */ ret = Unified2Write(aun); if (ret != 1) { goto error; } return 1; error: aun->length = 0; aun->offset = 0; return -1; }
/** * Note, this is the IP header, plus a bit of the original packet, not the whole thing! */ int DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) { /** Check the sizes, the header must fit at least */ if (len < IPV4_HEADER_LEN) { SCLogDebug("DecodePartialIPV4: ICMPV4_IPV4_TRUNC_PKT"); ENGINE_SET_INVALID_EVENT(p, ICMPV4_IPV4_TRUNC_PKT); return -1; } IPV4Hdr *icmp4_ip4h = (IPV4Hdr*)partial_packet; /** Check the embedded version */ if (IPV4_GET_RAW_VER(icmp4_ip4h) != 4) { /** Check the embedded version */ SCLogDebug("DecodePartialIPV4: ICMPv4 contains Unknown IPV4 version " "ICMPV4_IPV4_UNKNOWN_VER"); ENGINE_SET_INVALID_EVENT(p, ICMPV4_IPV4_UNKNOWN_VER); return -1; } /** We need to fill icmpv4vars */ p->icmpv4vars.emb_ipv4h = icmp4_ip4h; /** Get the IP address from the contained packet */ p->icmpv4vars.emb_ip4_src = IPV4_GET_RAW_IPSRC(icmp4_ip4h); p->icmpv4vars.emb_ip4_dst = IPV4_GET_RAW_IPDST(icmp4_ip4h); p->icmpv4vars.emb_ip4_hlen=IPV4_GET_RAW_HLEN(icmp4_ip4h) << 2; switch (IPV4_GET_RAW_IPPROTO(icmp4_ip4h)) { case IPPROTO_TCP: if (len >= IPV4_HEADER_LEN + TCP_HEADER_LEN ) { p->icmpv4vars.emb_tcph = (TCPHdr*)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_sport = ntohs(p->icmpv4vars.emb_tcph->th_sport); p->icmpv4vars.emb_dport = ntohs(p->icmpv4vars.emb_tcph->th_dport); p->icmpv4vars.emb_ip4_proto = IPPROTO_TCP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->TCP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); } else if (len >= IPV4_HEADER_LEN + 4) { /* only access th_sport and th_dport */ TCPHdr *emb_tcph = (TCPHdr*)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_tcph = NULL; p->icmpv4vars.emb_sport = ntohs(emb_tcph->th_sport); p->icmpv4vars.emb_dport = ntohs(emb_tcph->th_dport); p->icmpv4vars.emb_ip4_proto = IPPROTO_TCP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->TCP partial header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); } else { SCLogDebug("DecodePartialIPV4: Warning, ICMPV4->IPV4->TCP " "header Didn't fit in the packet!"); p->icmpv4vars.emb_sport = 0; p->icmpv4vars.emb_dport = 0; } break; case IPPROTO_UDP: if (len >= IPV4_HEADER_LEN + UDP_HEADER_LEN ) { p->icmpv4vars.emb_udph = (UDPHdr*)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_sport = ntohs(p->icmpv4vars.emb_udph->uh_sport); p->icmpv4vars.emb_dport = ntohs(p->icmpv4vars.emb_udph->uh_dport); p->icmpv4vars.emb_ip4_proto = IPPROTO_UDP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->UDP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); } else { SCLogDebug("DecodePartialIPV4: Warning, ICMPV4->IPV4->UDP " "header Didn't fit in the packet!"); p->icmpv4vars.emb_sport = 0; p->icmpv4vars.emb_dport = 0; } break; case IPPROTO_ICMP: if (len >= IPV4_HEADER_LEN + ICMPV4_HEADER_LEN ) { p->icmpv4vars.emb_icmpv4h = (ICMPV4Hdr*)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_sport = 0; p->icmpv4vars.emb_dport = 0; p->icmpv4vars.emb_ip4_proto = IPPROTO_ICMP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->ICMP header"); } break; } /* debug print */ #ifdef DEBUG char s[16], d[16]; PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_src), s, sizeof(s)); PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_dst), d, sizeof(d)); SCLogDebug("ICMPv4 embedding IPV4 %s->%s - PROTO: %" PRIu32 " ID: %" PRIu32 "", s,d, IPV4_GET_RAW_IPPROTO(icmp4_ip4h), IPV4_GET_RAW_IPID(icmp4_ip4h)); #endif return 0; }
/** * \internal * \brief Pseudo packet setup for flow forced reassembly. * * \param direction Direction of the packet. 0 indicates toserver and 1 * indicates toclient. * \param f Pointer to the flow. * \param ssn Pointer to the tcp session. * \param dummy Indicates to create a dummy pseudo packet. Not all pseudo * packets need to force reassembly, in which case we just * set dummy ack/seq values. */ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, int direction, Flow *f, TcpSession *ssn, int dummy) { p->datalink = DLT_RAW; p->proto = IPPROTO_TCP; FlowReference(&p->flow, f); p->flags |= PKT_STREAM_EST; p->flags |= PKT_STREAM_EOF; p->flags |= PKT_HAS_FLOW; p->flags |= PKT_PSEUDO_STREAM_END; if (direction == 0) p->flowflags |= FLOW_PKT_TOSERVER; else p->flowflags |= FLOW_PKT_TOCLIENT; p->flowflags |= FLOW_PKT_ESTABLISHED; p->payload = NULL; p->payload_len = 0; if (FLOW_IS_IPV4(f)) { if (direction == 0) { FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->src, &p->src); FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->dst, &p->dst); p->sp = f->sp; p->dp = f->dp; } else { FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->src, &p->dst); FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->dst, &p->src); p->sp = f->dp; p->dp = f->sp; } /* set the ip header */ p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p); /* version 4 and length 20 bytes for the tcp header */ p->ip4h->ip_verhl = 0x45; p->ip4h->ip_tos = 0; p->ip4h->ip_len = htons(40); p->ip4h->ip_id = 0; p->ip4h->ip_off = 0; p->ip4h->ip_ttl = 64; p->ip4h->ip_proto = IPPROTO_TCP; //p->ip4h->ip_csum = if (direction == 0) { p->ip4h->s_ip_src.s_addr = f->src.addr_data32[0]; p->ip4h->s_ip_dst.s_addr = f->dst.addr_data32[0]; } else { p->ip4h->s_ip_src.s_addr = f->dst.addr_data32[0]; p->ip4h->s_ip_dst.s_addr = f->src.addr_data32[0]; } /* set the tcp header */ p->tcph = (TCPHdr *)((uint8_t *)GET_PKT_DATA(p) + 20); SET_PKT_LEN(p, 40); /* ipv4 hdr + tcp hdr */ } else if (FLOW_IS_IPV6(f)) { if (direction == 0) { FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->src, &p->src); FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->dst, &p->dst); p->sp = f->sp; p->dp = f->dp; } else { FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->src, &p->dst); FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->dst, &p->src); p->sp = f->dp; p->dp = f->sp; } /* set the ip header */ p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p); /* version 6 */ p->ip6h->s_ip6_vfc = 0x60; p->ip6h->s_ip6_flow = 0; p->ip6h->s_ip6_nxt = IPPROTO_TCP; p->ip6h->s_ip6_plen = htons(20); p->ip6h->s_ip6_hlim = 64; if (direction == 0) { p->ip6h->s_ip6_src[0] = f->src.addr_data32[0]; p->ip6h->s_ip6_src[1] = f->src.addr_data32[1]; p->ip6h->s_ip6_src[2] = f->src.addr_data32[2]; p->ip6h->s_ip6_src[3] = f->src.addr_data32[3]; p->ip6h->s_ip6_dst[0] = f->dst.addr_data32[0]; p->ip6h->s_ip6_dst[1] = f->dst.addr_data32[1]; p->ip6h->s_ip6_dst[2] = f->dst.addr_data32[2]; p->ip6h->s_ip6_dst[3] = f->dst.addr_data32[3]; } else { p->ip6h->s_ip6_src[0] = f->dst.addr_data32[0]; p->ip6h->s_ip6_src[1] = f->dst.addr_data32[1]; p->ip6h->s_ip6_src[2] = f->dst.addr_data32[2]; p->ip6h->s_ip6_src[3] = f->dst.addr_data32[3]; p->ip6h->s_ip6_dst[0] = f->src.addr_data32[0]; p->ip6h->s_ip6_dst[1] = f->src.addr_data32[1]; p->ip6h->s_ip6_dst[2] = f->src.addr_data32[2]; p->ip6h->s_ip6_dst[3] = f->src.addr_data32[3]; } /* set the tcp header */ p->tcph = (TCPHdr *)((uint8_t *)GET_PKT_DATA(p) + 40); SET_PKT_LEN(p, 60); /* ipv6 hdr + tcp hdr */ } p->tcph->th_offx2 = 0x50; p->tcph->th_flags |= TH_ACK; p->tcph->th_win = 10; p->tcph->th_urp = 0; /* to server */ if (direction == 0) { p->tcph->th_sport = htons(f->sp); p->tcph->th_dport = htons(f->dp); if (dummy) { p->tcph->th_seq = htonl(ssn->client.next_seq); p->tcph->th_ack = htonl(ssn->server.last_ack); } else { p->tcph->th_seq = htonl(ssn->client.next_seq); p->tcph->th_ack = htonl(ssn->server.seg_list_tail->seq + ssn->server.seg_list_tail->payload_len); } /* to client */ } else { p->tcph->th_sport = htons(f->dp); p->tcph->th_dport = htons(f->sp); if (dummy) { p->tcph->th_seq = htonl(ssn->server.next_seq); p->tcph->th_ack = htonl(ssn->client.last_ack); } else { p->tcph->th_seq = htonl(ssn->server.next_seq); p->tcph->th_ack = htonl(ssn->client.seg_list_tail->seq + ssn->client.seg_list_tail->payload_len); } } if (FLOW_IS_IPV4(f)) { p->tcph->th_sum = TCPCalculateChecksum(p->ip4h->s_ip_addrs, (uint16_t *)p->tcph, 20); /* calc ipv4 csum as we may log it and barnyard might reject * a wrong checksum */ p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h, IPV4_GET_RAW_HLEN(p->ip4h)); } else if (FLOW_IS_IPV6(f)) { p->tcph->th_sum = TCPCalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->tcph, 20); } memset(&p->ts, 0, sizeof(struct timeval)); TimeGet(&p->ts); AppLayerSetEOF(f); return p; }