static int icmpv6_extract_err_infos(struct icmp_proto_info *info, uint8_t const *packet, size_t packet_len) { struct icmp_err *err = &info->err; struct ipv6_hdr const *iphdr = (struct ipv6_hdr *)packet; if (packet_len < sizeof(*iphdr)) { SLOG(LOG_DEBUG, "Bogus ICMPv6 packet too short for IPv6 header"); return -1; } err->protocol = READ_U8(&iphdr->next); ip_addr_ctor_from_ip6(err->addr+0, &iphdr->src); ip_addr_ctor_from_ip6(err->addr+1, &iphdr->dst); switch (iphdr->next) { case IPPROTO_TCP: case IPPROTO_UDP: if (packet_len >= sizeof(*iphdr) + 4) { info->set_values |= ICMP_ERR_PORT_SET; return icmp_extract_err_ports(err, packet + sizeof(*iphdr)); } break; default: SLOG(LOG_DEBUG, "ICMPv6 Error for unsuported protocol %u", iphdr->next); break; } 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; }