Jump to content
  • Advertisement
Sign in to follow this  
pindrought

Accepting IPv4 connections as IPv6 Server

Recommended Posts

Posted (edited)

I am trying to accept IPv4 connections on my server that is listening on an IPv6 TCP socket.

 

I was currently working on porting a blocking socket example i'm using for some tutorials i've been making, and i've noticed behavior that I did not expect.

Current github dev branch: https://github.com/Pindrought/PNet/tree/TCP_Blocking_Winsock_Tutorial_17Dev

My client is connecting using an IPv4 socket.

My server is accepting connections on an ipv6 socket, and i've disabled the IPV6_V6ONLY socket option to allow both ipv4 and ipv6 incoming connections.

 

The connections are accepted just fine - the confusion for me arises in the fact that the accepted connection appears to be an IPv6 connection according to the address family in the sockaddr struct.

https://github.com/Pindrought/PNet/blob/TCP_Blocking_Winsock_Tutorial_17Dev/PNet/PNet/Socket.cpp#L128-L145

 

I was under the impression that the ipv4 connection would have an address family of AF_INET6.

Is this expected behavior? I just want to make sure that i'm not doing anything wrong here. If this is expected behavior, is there any way I can determine from the server side if the connecting client did so using IPv4 or IPv6?

 

Thanks!

Edited to add:

This is the output my server has

Quote

Winsock api successfully initialized.
Socket successfully created.
Socket successfully listening on port 4790.
New IPv6 connection accepted!
IP Version: IPv6
Hostname: ::ffff:127.0.0.1
IP: ::ffff:127.0.0.1
Port: 59191
IP bytes...
0
0
0
0
0
0
0
0
0
0
255
255
127
0
0
1
New connection accepted.

 

 

Edited by pindrought

Share this post


Link to post
Share on other sites
Advertisement
Posted (edited)

For a dual-stack socket, the only differentiation between IPv6 and IPv4 traffic is the "format" of the IPv6 IP address.  Everything is handled on (your) code side as IPv6 (AF_INET6).  The only thing that is different is that IPv4 traffic will have a special "mapped" IPv6 IP address (the ::ffff:x.x.x.x format you see above).  To send IPv4 traffic you need to translate to that mapped address (in your case just use the same address that connected), and if you care you can check to see if the received connection/traffic is IPv4 by checking to see if the upper 12 bytes of the address match 0000:0000:0000:0000:0000:ffff.  The lower 4 bytes of the IPv6 address will be the IPv4 IP address.

This page lays it out clearly (and references a few handy Microsoft/windows-specific macros for checking for and translating between IPv6 mapped addresses and IPv4, presuming you are doing a win32 project):

https://docs.microsoft.com/en-us/windows/desktop/winsock/dual-stack-sockets

 

Edited by SBD

Share this post


Link to post
Share on other sites

 

7 minutes ago, SBD said:

For a dual-stack socket, the only differentiation between IPv6 and IPv4 traffic is the "format" of the IPv6 IP address.  Everything is handled on (your) code side as IPv6 (AF_INET6).  The only thing that is different is that IPv4 traffic will have a special "mapped" IPv6 IP address (the ::ffff:x.x.x.x format you see above).  To send IPv4 traffic you need to translate to that mapped address (in your case just use the same address that connected), and if you care you can check to see if the received connection/traffic is IPv4 by checking to see if the upper 12 bytes of the address match 0000:0000:0000:0000:0000:ffff.  The lower 4 bytes of the IPv6 address will be the IPv4 IP address.

This page lays it out clearly (and references a few handy Microsoft/windows-specific macros for checking for and translating between IPv6 mapped addresses and IPv4, presuming you are doing a win32 project):

https://docs.microsoft.com/en-us/windows/desktop/winsock/dual-stack-sockets

 

Great reply! This makes perfect sense. Thanks so much for the detailed explanation.

Share this post


Link to post
Share on other sites

A quick suggestion is to allow a layer 4 proxy like haproxy to handle the dual stack side for you. There are a ton of possible benefits to this as an abstraction layer - managing ports, ipv4/ipv6, security, logging and monitoring etc. Most importantly is it lets you get back to completing the game.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!