Estoy tratando de enviar un encabezado IPv6 personalizado a través de un socket RAW en C Linux.
Ya tuve éxito en IPv4 usando la opción de socket IP_HDRINCL, sin embargo, no hay un equivalente para IPv6.
Encontré una solución alternativa aquí que sugiere usar socket(AF_INET6, SOCK_RAW, IPPROTO_RAW) para tener el mismo efecto que habilitar la opción de socket IP_HDRINCL.
El socket se creó con éxito y no obtengo ningún error hasta que uso la función sendto con mi encabezado modificado.
Configuro el socket de esta manera:
static int socketFd = 0; static struct sockaddr_in6 remote; int main() { socketFd = socket (PF_INET6, SOCK_RAW, IPPROTO_RAW); if (socketFd < 0) { printf ("An error ocurred while creating the socket.\n"); exit (2); } remote.sin6_family = AF_INET6; remote.sin6_port = htons (25000); if (inet_pton (AF_INET6, "fd00:c0de::70d6:4ab9:115d:8cda", &(remote.sin6_addr)) != 1) { close (socketFd); printf ("Unable to parse IPv6 address.\n"); exit (2); } /*More code */ ... return 0; } Y luego, tengo esta función de devolución de llamada que debería enviar mis paquetes IPv6 personalizados pero sendto falla al devolver EINVAL.
static void sendPacket () { char buffer[BUFSIZ]; const size_t len = sizeof(struct ip6_hdr) + sizeof(struct UDP_hdr); struct ip6_hdr *ip6 = (struct ip6_hdr*) (buffer); struct UDP_hdr *udp = (struct UDP_hdr *) (buffer + sizeof(struct ip6_hdr)); memset (buffer, 0, BUFSIZ); ip6->ip6_ctlun.ip6_un2_vfc = 0x60; ip6->ip6_dst = remote.sin6_addr; ip6->ip6_flow = 60; ip6->ip6_hops = 64; ip6->ip6_nxt = 17; ip6->ip6_plen = sizeof(struct UDP_hdr); if (inet_pton (AF_INET6, "fd00:c0de::62a4:4cff:1234:5678", &(ip6->ip6_src)) != 1) { printf ("Error while parsing spoofed IPv6 address.\n"); return; } // Fabricate the UDP header. Source port number, redundant udp->uh_sport = htons (21000); // Destination port number udp->uh_dport = remote.sin6_port; udp->uh_ulen = htons (sizeof(struct UDP_hdr)); if (sendto (socketFd, buffer, len, 0, (struct sockaddr *) &remote, sizeof(remote)) < 0) { perror ("sendto"); printf ("Error while sending packet.\n"); } }He depurado el programa y todos los valores en la estructura ip6_hdr parecen ser correctos y también los de la estructura UDP_hdr. ¿Me estoy perdiendo de algo?
Para quien pueda ser útil, obtuve un código similar para trabajar, pero abriendo el socket en su lugar con
socket(test->state.addr_family, SOCK_RAW, IPPROTO_UDP);Configuración de las opciones con
int val = 1; ret = setsockopt(test->state.sockfd, IPPROTO_IPV6, IPV6_HDRINCL, &val, sizeof (val)); y poniendo el puerto a cero con remote.sin6_port = 0; , como se explica aquí para evitar el error EINVAL en la llamada de sendto .
Bien, entonces encontré una solución. Para cualquiera que tenga problemas con esto, la forma en que lo resolví fue usando la biblioteca Pcap (seguí este ejemplo). Sin embargo, para aquellos que deben usar AF_PACKETS, encontré un ejemplo muy completo que usa sockets RAW para lograr esto en este enlace .