tcp_ipv6_v6only.c 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #include <arpa/inet.h>
  2. #include <errno.h>
  3. #include <netinet/in.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sys/socket.h>
  8. #include <sys/types.h>
  9. #include <unistd.h>
  10. /* use the same loopback address and port for both IPV6 and IPV4 */
  11. #define SRV_IPV6 "::1/128"
  12. #define SRV_IPV4 "127.0.0.1"
  13. #define PORT 11112
  14. int main(int argc, char** argv) {
  15. int socket_ipv4;
  16. int socket_ipv6;
  17. int ret;
  18. if ((socket_ipv6 = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
  19. perror("socket(ipv6)");
  20. return 1;
  21. }
  22. if ((socket_ipv4 = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  23. perror("socket(ipv4)");
  24. return 1;
  25. }
  26. int enable = 1;
  27. if (setsockopt(socket_ipv6, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) {
  28. perror("setsockopt(ipv6, SO_REUSEADDR = 1)");
  29. return 1;
  30. }
  31. if (setsockopt(socket_ipv4, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) {
  32. perror("setsockopt(ipv4, SO_REUSEADDR = 1)");
  33. return 1;
  34. }
  35. /* this forces IPV6 to listen for both IPV4 and IPV6 connections; this in turn makes binding
  36. * another (IPV4) socket on the same port meaningless and results in -EADDRINUSE */
  37. int disable = 0;
  38. if (setsockopt(socket_ipv6, IPPROTO_IPV6, IPV6_V6ONLY, &disable, sizeof(disable)) < 0) {
  39. perror("setsockopt(IPV6_V6ONLY = 0)");
  40. return 1;
  41. }
  42. struct sockaddr_in6 address_ipv6;
  43. memset(&address_ipv6, 0, sizeof(address_ipv6));
  44. address_ipv6.sin6_family = AF_INET6;
  45. address_ipv6.sin6_port = htons(PORT);
  46. if (inet_pton(AF_INET6, SRV_IPV6, &address_ipv6.sin6_addr) < 0) {
  47. perror("inet_pton(ipv6)");
  48. return 1;
  49. }
  50. if (bind(socket_ipv6, (struct sockaddr*)&address_ipv6, sizeof(address_ipv6)) < 0) {
  51. perror("bind(ipv6)");
  52. return 1;
  53. }
  54. /* we must start listening on IPV6 socket to make it active and kick in Linux rules for bind() */
  55. if (listen(socket_ipv6, 3) < 0) {
  56. perror("listen(ipv6)");
  57. return 1;
  58. }
  59. struct sockaddr_in address_ipv4;
  60. memset(&address_ipv4, 0, sizeof(address_ipv4));
  61. address_ipv4.sin_family = AF_INET;
  62. address_ipv4.sin_port = htons(PORT); /* note the same port! */
  63. if (inet_pton(AF_INET, SRV_IPV4, &address_ipv4.sin_addr) < 0) {
  64. perror("inet_pton(ipv4)");
  65. return 1;
  66. }
  67. ret = bind(socket_ipv4, (struct sockaddr*)&address_ipv4, sizeof(address_ipv4));
  68. if (ret != -1 || errno != EADDRINUSE) {
  69. fprintf(stderr, "bind(ipv4) was successful even though there is no IPV6_V6ONLY on same port\n");
  70. return 1;
  71. }
  72. puts("test completed successfully");
  73. return 0;
  74. }