static int icmp_extract_err_infos(struct icmp_proto_info *info, uint8_t const *packet, size_t packet_len) { struct icmp_err *err = &info->err; if (packet_len < 20 + 8) { SLOG(LOG_DEBUG, "Bogus ICMP err : packet too short for IP header"); return -1; } struct ip_hdr const *iphdr = (struct ip_hdr const *)packet; size_t iphdr_len = iphdr->hdr_len * 4; if (iphdr_len > packet_len - 8) { SLOG(LOG_DEBUG, "Bogus ICMP packet IP header too long (%zu > %zu)", iphdr_len, packet_len = 8); return -1; } err->protocol = iphdr->protocol; ip_addr_ctor_from_ip4(err->addr+0, iphdr->src); ip_addr_ctor_from_ip4(err->addr+1, iphdr->dst); switch (iphdr->protocol) { case IPPROTO_TCP: case IPPROTO_UDP: info->set_values |= ICMP_ERR_PORT_SET; return icmp_extract_err_ports(err, packet + iphdr_len); default: SLOG(LOG_DEBUG, "ICMP Error for unsuported protocol %u", iphdr->protocol); return 0; } }
int ip_addr_ctor_from_sockaddr(struct ip_addr *ip, struct sockaddr const *addr, socklen_t addrlen) { switch (addr->sa_family) { case AF_INET: { struct sockaddr_in *ip_addr = (struct sockaddr_in *)addr; if (addrlen < sizeof(*ip_addr)) { SLOG(LOG_NOTICE, "Invalid AF_INET sockaddr of size %zu", (size_t)addrlen); return -1; } ip_addr_ctor_from_ip4(ip, ip_addr->sin_addr.s_addr); return 0; } case AF_INET6: { struct sockaddr_in6 *ip_addr = (struct sockaddr_in6 *)addr; if (addrlen < sizeof(*ip_addr)) { SLOG(LOG_NOTICE, "Invalid AF_INET6 sockaddr of size %zu", (size_t)addrlen); return -1; } ip_addr_ctor_from_ip6(ip, &ip_addr->sin6_addr); return 0; } } SLOG(LOG_DEBUG, "Unknown sockaddr family %u", (unsigned)addr->sa_family); return -1; }
static enum proto_parse_status read_channel(struct skinny_parser *parser, unsigned from, struct skinny_proto_info *info, struct cursor *curs, struct timeval const *now) { assert(from == FROM_MGR || from == FROM_STATION); if (curs->cap_len < 4+16+4) return PROTO_TOO_SHORT; uint32_t ip_version = cursor_read_u32le(curs); if (ip_version == 0) { // v4 uint32_t ip = cursor_read_u32(curs); ip_addr_ctor_from_ip4(&parser->peer[from], ip); cursor_drop(curs, 12); // this field is 16 bytes in length } else if (ip_version == 1) { // v16 ip_addr_ctor_from_ip6(&parser->peer[from], (struct in6_addr const *)curs->head); cursor_drop(curs, 16); } else { SLOG(LOG_DEBUG, "Invalid IP version (%d)", ip_version); return PROTO_PARSE_ERR; } parser->port[from] = cursor_read_u32le(curs); parser->media_set[from] = true; try_cnxtrack(parser, now); // Copy these into the info block SLOG(LOG_DEBUG, "Got media info"); info->set_values |= SKINNY_MEDIA_CNX; info->media_ip = parser->peer[from]; info->media_port = parser->port[from]; return PROTO_OK; }
static enum proto_parse_status read_channel(struct skinny_parser *parser, unsigned from, struct skinny_proto_info *info, struct cursor *curs, struct timeval const *now) { assert(from == FROM_MGR || from == FROM_STATION); if (curs->cap_len < 4+16+4) return PROTO_TOO_SHORT; uint32_t ip_version = 0; // The ip field has a 16 byte lenght on CM7 headers. We // need to drop some bytes before parsing remote port short offset_ip_port = 0; switch (info->header_ver) { case SKINNY_BASIC: break; case SKINNY_CM7_TYPE_A: case SKINNY_CM7_TYPE_B: case SKINNY_CM7_TYPE_C: ip_version = cursor_read_u32le(curs); // We drop (16 - 4) for ipv4 and (16 - 8) for ipv6 offset_ip_port = ip_version ? 8 : 12; break; } if (ip_version == 0) { // v4 uint32_t ip = cursor_read_u32(curs); ip_addr_ctor_from_ip4(&parser->peer[from], ip); } else if (ip_version == 1) { // v6 ip_addr_ctor_from_ip6(&parser->peer[from], (struct in6_addr const *)curs->head); } else { SLOG(LOG_DEBUG, "Invalid IP version (%d)", ip_version); return PROTO_PARSE_ERR; } cursor_drop(curs, offset_ip_port); parser->port[from] = cursor_read_u32le(curs); parser->media_set[from] = true; try_cnxtrack(parser, now); // Copy these into the info block SLOG(LOG_DEBUG, "Got media info"); info->set_values |= SKINNY_MEDIA_CNX; info->media_ip = parser->peer[from]; info->media_port = parser->port[from]; return PROTO_OK; }
static enum proto_parse_status dhcp_parse(struct parser *parser, struct proto_info *parent, unsigned way, uint8_t const *payload, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet) { struct dhcp const *dhcp = (struct dhcp *)payload; // Sanity Checks // Check that we have at least the size of an DHCP packet for IP protocol if (wire_len < sizeof(*dhcp)) return PROTO_PARSE_ERR; // And that we have enough data to parse it if (cap_len < sizeof(*dhcp)) return PROTO_TOO_SHORT; if (0 != memcmp(dhcp->cookie, &magic_cookie, sizeof(magic_cookie))) { SLOG(LOG_DEBUG, "Bad magic Cookie"); return PROTO_PARSE_ERR; } struct dhcp_proto_info info; proto_info_ctor(&info.info, parser, parent, wire_len, 0); info.opcode = READ_U8(&dhcp->op); if (info.opcode != BOOTP_REQUEST && info.opcode != BOOTP_REPLY) { SLOG(LOG_DEBUG, "Unknown DHCP opcode (%u)", info.opcode); return PROTO_PARSE_ERR; } uint8_t const hlen = READ_U8(&dhcp->hlen); if (hlen > sizeof(dhcp->chaddr)) { SLOG(LOG_DEBUG, "Bad hlen in DHCP (%u)", hlen); return PROTO_PARSE_ERR; } info.xid = READ_U32N(&dhcp->xid); info.set_values = 0; uint32_t const addr = READ_U32(&dhcp->yiaddr); if (addr) { info.set_values |= DHCP_CLIENT_SET; ip_addr_ctor_from_ip4(&info.client, addr); } uint8_t const htype = READ_U8(&dhcp->htype); info.hw_addr_is_eth = htype == 1; if (info.hw_addr_is_eth) { if (hlen != sizeof(info.client_mac)) { SLOG(LOG_DEBUG, "Bad hlen (%u) for Eth type", hlen); return PROTO_PARSE_ERR; } memcpy(info.client_mac, dhcp->chaddr, sizeof(info.client_mac)); } else { memset(info.client_mac, 0, sizeof(info.client_mac)); } memcpy(info.server_name, dhcp->sname, sizeof(info.server_name)); SLOG(LOG_DEBUG, "New DHCP %s", dhcp_opcode_2_str(info.opcode)); // parse options info.msg_type = 0; // mandatory struct cursor c; cursor_ctor(&c, dhcp->options, cap_len - offsetof(struct dhcp, options)); while (c.cap_len >= 2) { uint8_t const type = cursor_read_u8(&c); uint8_t const len = cursor_read_u8(&c); if (c.cap_len < len) { SLOG(LOG_DEBUG, "Cannot read options"); return PROTO_PARSE_ERR; } switch (type) { case 53: // msg type if (len != 1) { SLOG(LOG_DEBUG, "Bad length (%"PRIu8") for msg type DHCP option", len); return PROTO_PARSE_ERR; } info.msg_type = cursor_read_u8(&c); if (info.msg_type > DHCP_INFORM) { SLOG(LOG_DEBUG, "Bad DHCP msg type (%u)", info.msg_type); return PROTO_PARSE_ERR; } break; default: cursor_drop(&c, len); break; } } if (0 == info.msg_type) { // not found SLOG(LOG_DEBUG, "DHCP msg without msg type"); return PROTO_PARSE_ERR; } return proto_parse(NULL, &info.info, way, NULL, 0, 0, now, tot_cap_len, tot_packet); }