Мне было интересно, можно ли на Ubuntu 12.04 отправить UDP-пакет из сокета с адресом локальной сети IPv6 на устройство в той же беспроводной сети, используя его IPv4 адрес. Я уже успел отправить UDP-пакет в этот целевой интерфейс, используя его IPv6-адрес.Отправить UDP на локальный ipv4-адрес с помощью локального сокета ipv6
У меня есть сокет с адресом IPv6, IPv6ONLY не установлен:
int fd = socket(AF_INET6, SOCK_DGRAM, 0);
int no = 0;
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&no, sizeof(no));
bind(fd, (sockaddr*)&sa, sizeof(sa));
Я просто отправить сверстнику с SendTo:
struct sockaddr_in6 peer = create_ipv6_sockaddr(55555, "193.156.108.67", 0, 0, true);
sendto(sock,content,strlen(content),0,(struct sockaddr*)&peer,sizeof(peer));
Эта функция создает sockaddr_in6:
sockaddr_in6 create_ipv6_sockaddr(int port, string addr, uint32_t flowinfo, uint32_t scope_id, bool ipv4=false) {
struct sockaddr_in6 si;
si.sin6_family = AF_INET6;
if (ipv4) {
si.sin6_family = AF_INET;
}
si.sin6_port = htons(port);
si.sin6_flowinfo = flowinfo; // Should be 0 or 'random' number to distinguish this flow
if (ipv4) {
addr = "::ffff:" + addr;
}
inet_pton(AF_INET6, addr.c_str(), &si.sin6_addr);
if (!si.sin6_addr.s6_addr) {
perror("Address is wrong..");
}
si.sin6_scope_id = scope_id;
return si;
}
В принципе, если адрес является адресом IPv4, я добавляю его ::ffff:
и Я установил семейство AF_INET.
Это возможно. Если да, то что я делаю неправильно?
EDIT:
Резюмируя, сообщение IPv4 не может отправить, если сокет IPv6 связан с конкретным IP (или интерфейс, не уверен, какой). Поэтому гнездо IPv6 должно использовать подстановочный знак ::0
. Семейство структуры sockaddr_in6 должно по-прежнему быть AF_INET6 с добавленным ::ffff:
. Код не будет возвращать отказ, если используется AF_INET4, но по моему опыту никакого фактического сообщения не отправлено.
Действительно, если вы создаете структуру sockaddr самостоятельно, вы получаете ее из getaddrinfo, вы сможете передать ее непосредственно в гнездо подстановочного IPv6 для отправки.
ИЗМЕНИТЬ ЛЕТ СПУСТЯ:
По желанию, @Erfan, я откопал код. Я боюсь сказать, что я больше не понимаю все это, и я не могу сказать, действительно ли это работает.
sockaddr_in6 create_ipv6_sockaddr(int port, string addr, uint32_t flowinfo, uint32_t scope_id, bool ipv4=false) {
struct sockaddr_in6 si;
si.sin6_family = AF_INET6;
// if (ipv4) {
// si.sin6_family = AF_INET;
// }
si.sin6_port = htons(port);
si.sin6_flowinfo = flowinfo; // Should be 0 or 'random' number to distinguish this flow
if (ipv4) {
addr = "::ffff:" + addr;
}
inet_pton(AF_INET6, addr.c_str(), &si.sin6_addr);
if (!si.sin6_addr.s6_addr) {
perror("Address is wrong..");
}
// char s[40];
// inet_ntop(AF_INET6, &(si.sin6_addr), s, sizeof(s));
// fprintf(stderr, "Sockaddr %d %s\n", si.sin6_family, s);
si.sin6_scope_id = scope_id;
if (scope_id == 0 && !ipv4) {
si.sin6_scope_id = ipv6_to_scope_id(&si); // Interface number
}
return si;
}
int ipv6_to_scope_id(sockaddr_in6 *find) {
struct ifaddrs *addrs, *iap;
struct sockaddr_in6 *sa;
char host[NI_MAXHOST];
getifaddrs(&addrs);
for (iap = addrs; iap != NULL; iap = iap->ifa_next) {
if (iap->ifa_addr && (iap->ifa_flags & IFF_UP) && iap->ifa_addr->sa_family == AF_INET6) {
sa = (struct sockaddr_in6 *)(iap->ifa_addr);
if (memcmp(&find->sin6_addr.s6_addr, &sa->sin6_addr.s6_addr, sizeof(sa->sin6_addr.s6_addr)) == 0) {
getnameinfo(iap->ifa_addr, sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
fprintf(stderr, "Found interface %s with scope %d\n", host, sa->sin6_scope_id);
return sa->sin6_scope_id;
}
}
}
freeifaddrs(addrs);
return 0;
}
И связывать:
int bind_ipv6 (sockaddr_in6 sa) {
int fd = socket(AF_INET6, SOCK_DGRAM, 0);
if (fd < 0) {
perror("Creating socket failed");
}
char str[40];
inet_ntop(AF_INET6, &(sa.sin6_addr), str, sizeof(str));
// fprintf(stderr, "Bind to %s:%d\n", str, ntohs(sa.sin6_port));
int no = 0;
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&no, sizeof(no)) < 0) { // Only works with wildcard
perror("V6ONLY failed");
}
if (bind(fd, (sockaddr*)&sa, sizeof(sa)) < 0) {
perror("Binding failed");
}
return fd;
}
есть примеры сырого сокета здесь: http://www.pdbuchan.com/rawsock/rawsock.html. inet_pton вызывается с AF_INET в случае IPV4 в примере udp6_to4.c – lucasg