I have created IPv6 support for Quake 3. If you compile the code with -
DENABLE_IPV6 a "multistack" Quake 3 is created (supports both IPv4 and IPv6).
Otherwise only IPv4 is supported.
I am a Linux developer - that means only Unix net code is patched. Someone
should write a patch for Windows too.
I think that this patch should be tested first as there might be bugs.
Patch supports TCPv6 ports in three variants:
1) 3ffe::abca:5::27960
2) 3ffe::abca:5@27960
3) [3ffe::abca:5]:27960
Patch should support local IPv6 network scanning (untested!).
There is currently one limitation. IPv6 banning is not supported (g_svcmds.c). I
can write the patch later if required.
I cleaned up the patch issue, but:
In code/qcommon/net_chan.c, your patch has this:
- // inet_addr returns this if out of range
- if ( a->ip[0] == 255 && a->ip[1] == 255 && a->ip[2] == 255 && a->ip[3]
== 255 ) {
- a->type = NA_BAD;
- return qfalse;
- }
-
...is that safe to remove in the ipv4 case?
--ryan.
Created attachment 774[details]
Same patch, updated for latest subversion revision...
Here's the same patch, just changed to apply cleanly to latest revision.
Just need an answer on that one chunk of code...
--ryan.
Well, it shouldn't be removed because of Windows code. Windows code still uses
obsolete inet_addr() which returns 0xffffffff on failure and I don't have enough
energy to fight with that ugly win_net.c code (ugly when compared to unix_net.c
code).
And you can remove this from patch (both in NET_StringToAdr):
Com_Printf("address: %s\n", base);
Com_Printf("address2: %s\n", base);
I've added them when I was debugging...
I haven't mentioned another limitation of my IPv6 implementation yet. Connect
will fail if you use Multiplayer-Specify dialog and use port shorter than 5
characters. This has a simple reason - some (probably) script creates an address
by appending ":port" to IP address and then calls CL_Connect_f().
So the program must make a guess: is that ":xxxx" at the end of address port or
a portion of IPv6 address? When there are >4 characters it is definitely port.
Default Q3 port is 5 chars long so it shouldn't bother many people. They can
still use "/connect" in console for shorter ports...
Another small thing in Sys_IsLANAddress():
if(adr.ip6[0] == 0xfe && adr.ip6[1] == 0x80)
should be
if(adr.ip6[0] == 0xfe && (adr.ip6[1] & 0xc0) == 0x80)
I have overlooked the rank size while reading RFC. Local link scope is
fe80::/10, not fe80::/16. IPv6 ranks are real mess... :(
I hope that all problems are fixed now.
"I haven't mentioned another limitation of my IPv6 implementation yet. Connect
will fail if you use Multiplayer-Specify dialog and use port shorter than 5
characters. This has a simple reason - some (probably) script creates an
address by appending ":port" to IP address and then calls CL_Connect_f()."
I have a little fix for that in my IPv6 patch, which uses '[]' encapsulation
for IPv6 addresses, the same way browsers and scp do it;
/connect [2001:470:1f00:488:1::1]:2781
would then work. The only place this really matters (as far as I can tell so
far) is Sys_StringToSockaddr.
I'm not sure how to 'attach', so, here's the routine;
--SNIP--
qboolean Sys_StringToSockaddr (const char *s, struct sockaddr_storage
*sadr) {
char copy[128];
char *addrs, *space;
char *ports = NULL;
int err;
struct addrinfo hints;
struct addrinfo *resultp;
memset (&hints,0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM;
hints.ai_family = PF_UNSPEC;
strcpy (copy, s);
addrs = space = copy;
if (*addrs == '[') {
addrs++;
for (; *space && *space != ']'; space++);
if (!*space) {
Com_Printf ("NET_StringToSockaddr: invalid IPv6 address
%s\n", s);
return 0;
}
*space++ = '\0';
}
for (; *space; space++) {
if (*space == ':') {
*space = '\0';
ports = space + 1;
}
}
if ((err = getaddrinfo (addrs, ports, &hints, &resultp))) {
// Error
Com_Printf ("NET_StringToSockaddr: string %s:\n%s\n", s,
gai_strerror(err));
return 0;
}
switch (resultp->ai_family) {
case AF_INET:
// convert to ipv4 addr
memset (sadr, 0, sizeof (struct sockaddr_storage));
memcpy (sadr, resultp->ai_addr, resultp->ai_addrlen);
break;
case AF_INET6:
// convert to ipv6 addr
memset (sadr, 0, sizeof (struct sockaddr_storage));
memcpy (sadr, resultp->ai_addr, resultp->ai_addrlen);
break;
default:
Com_Printf
("NET_StringToSockaddr: string %s:\nprotocol
family %d not supported\n",
s, resultp->ai_family);
return 0;
}
return qtrue;
}
--SNIP--
wow, i missed this:
"Patch supports TCPv6 ports in three variants:
1) 3ffe::abca:5::27960
2) 3ffe::abca:5@27960
3) [3ffe::abca:5]:27960"
are you sure 1 and 2 are good ideas? i think if we stick with 3, the standard,
we should be fine.
and in the case of 1, we assume default port and don't check for one, if we
even allow it?
"are you sure 1 and 2 are good ideas?"
Well, I don't know whether are they standard or not but I've seen them...
"and in the case of 1, we assume default port and don't check for one, if we
even allow it?"
Yes, we check for the port - we don't assume anything:
NET_StringToAdr(...)
{
//...
if(*(port-1) == ':' && strstr(base, "::") != port-1) // there are more ::
{
// "3ffe:80ee:3309::1::2222" -> "3ffe:80ee:3309::1\0:2222"
*(port-1) = 0; // zero the first : in the last ::
}
// ...
// "port" still points to the ':'
if(port)
{
// "3ffe:80ee:3309::1\0:2222" -> "3ffe:80ee:3309::1\0\02222"
// ^ -> ^
*port = 0;
port++; // "port" now points to the port
}
// convert port to integer....
"I have a little fix for that in my IPv6 patch..."
/connect [....]:port should work anyway...
But I have found a small problem in my code. Site-local addresses are treated as
global addresses.
in Sys_IsLANAddress():
if(adr.ip6[0] == 0xfe && (adr.ip6[1] & 0xc0) == 0x80)
--should be--
if(adr.ip6[0] == 0xfe && ( (adr.ip6[1] & 0xc0) == 0x80 || (adr.ip6[1] & 0xc0) ==
0xc0))
Okay, something I've found in my patch which may incarnate in your patch as
well just by glancing through net_chan.c ~line 750, if no port is specified,
will it use the last quad as the port?
For example, /connect 2001:470:1f00:488:1::102
"if no port is specified,
will it use the last quad as the port?"
Nope. This combination finds out whether there are more '::' in the string.
Notice the strRchr()...
port = strrchr( base, ':' ); // find last ':'
// ...
// if (port-1) points to the last '::' compare it to the address of first '::'
if(*(port-1) == ':' && strstr(base, "::") != port-1) // there are more ::
Comment 13Patryk Szczyglowski
2005-11-08 06:21:04 EST
Those bastards have copied and edited my code...they wrote the Win32 part, but the most of the rest is my code.
Have a look in their patch for this string:
+#endif // well, we can use getnameinfo for IPv4 too...but let's leave it as it is (for sure)
I wrote this note! Not they...
- NET_GetLocalAddress in unix_net.c hasn't been ported yet.
What a big surprise...I haven't ported it too...
They could at least say that this isn't fully their work and not just "Hexago ©2004"
Comment 15Patryk Szczyglowski
2005-11-08 18:35:34 EST
(In reply to comment #14)
> Those bastards have copied and edited my code...they wrote the Win32 part, but
> the most of the rest is my code.
[...]
>
> They could at least say that this isn't fully their work and not just "Hexago
> ©2004"
>
Have a look at http://www.hexago.com/docs/doc_20051018-37.pdf:
"Thanks to Lubos Dolezel for providing a first patch for IPv6
support and to Florent Parent for his help with the port."
Anyway, I have a patch for their patch ;)
(In reply to comment #15)
> (In reply to comment #14)
> > Those bastards have copied and edited my code...they wrote the Win32 part, but
> > the most of the rest is my code.
> [...]
> >
> > They could at least say that this isn't fully their work and not just "Hexago
> > ©2004"
> >
>
> Have a look at http://www.hexago.com/docs/doc_20051018-37.pdf:
> "Thanks to Lubos Dolezel for providing a first patch for IPv6
> support and to Florent Parent for his help with the port."
>
> Anyway, I have a patch for their patch ;)
Sorry guys, it completely got out of my mind to post the patch here. Patryk, did you really produce a new patch or I should post mine here? Anyway, I should update it from the lastest svn.
There's still some work to put on this to have it handle multicast properly. I still get some errors from sendto when sending multicast on Windows, even if the join to the group seems to work.
Lubos, I apologize for not mentioning you are the original author of the patch on the page, it must have been lost in the copy-paste of the text. I intended mention it, as it was in the pdf doc. I'll add it to the page as soon as I get a chance.
Comment 18Patryk Szczyglowski
2005-12-09 14:06:13 EST
(In reply to comment #16)
> Sorry guys, it completely got out of my mind to post the patch here. Patryk,
> did you really produce a new patch or I should post mine here? Anyway, I should
> update it from the lastest svn.
My fix is a litlle one-liner for a condition, where ipv6 support is not compiled in linux kernel. It bails out on "socket family not supported". I made him to simply gave up after some tries and continue with ipv4 socket only. Seems to work :)
Comment 19Patryk Szczyglowski
2005-12-09 14:07:53 EST
Created attachment 823[details]
Give up ipv6 and continue when inet6 socket family is not available
Setting a QA contact on all ioquake3 bugs, even resolved ones. Sorry if you get a flood of email from this, it should only happen once. Apologies for the incovenience.
--ryan.
Created attachment 772 [details] IPv6 patch (tar.bz2)
Created attachment 774 [details] Same patch, updated for latest subversion revision... Here's the same patch, just changed to apply cleanly to latest revision. Just need an answer on that one chunk of code... --ryan.
Created attachment 822 [details] Patch with multicast based on the first.
Created attachment 823 [details] Give up ipv6 and continue when inet6 socket family is not available