[PATCH] remove zone identifier for IPv6 link-local addresses
Fabian Hugelshofer
hugelshofer2006 at gmx.ch
Sun Jun 28 17:28:01 UTC 2009
On Fri, 2009-06-26 at 15:43 -0500, Rob Landley wrote:
> On Friday 26 June 2009 04:31:57 Fabian Hugelshofer wrote:
> > IPv6 knows scoped address types i.e. link and site local addresses. Link
> > local addresses can have a scope identifier to specify the
> > interface/link an address is valid on (e.g. fe80::1%eth0). This scope
> > identifier is only valid on a single node.
> >
> > RFC 4007 says that the scope identifier must not be sent across the
> > wire, unless every node agrees on the semantics (which is not the case
> > for link-local zones). Apache e.g. rejects HTTP requests with a scope
> > identifier in the host header (see
> > https://issues.apache.org/bugzilla/show_bug.cgi?id=35122).
> >
> > This patch removes the scope identifier from the HTTP request, whereas
> > it remains in the structure used to connect to the server.
> >
> > Signed-off-by: <hugelshofer2006 at gmx.ch>
> >
> > Regards,
> >
> > Fabian
> > diff --git a/networking/wget.c b/networking/wget.c
> > index ca3acd0..852e628 100644
> > --- a/networking/wget.c
> > +++ b/networking/wget.c
> > @@ -340,6 +340,57 @@ static void parse_url(char *src_url, struct host_info
> > *h) sp = h->host;
> > }
> >
> > +/* RFC 4007 sais that the scope identifier MUST NOT be sent accross the
> > wire, + * unless all nodes agree on the semantic. Apache e.g. regards zone
> > identifiers + * in the Host header as invalid requests, see
> > + * https://issues.apache.org/bugzilla/show_bug.cgi?id=35122
> > + */
> > +static void strip_ipv6_scope(struct host_info *h)
> > +{
> > + char *scope, *cp;
> > +
> > + /* Remove the IPv6 zone identifier from the host address,
> > + * ugly parsing like in str2sockaddr() */
> > +
> > + if (!ENABLE_FEATURE_IPV6) {
> > + /* only for ipv6 */
> > + return;
> > + }
>
> Um, that's not how ENABLE stuff works. We're not just trying to disable
> functionality, we're trying to save storage and memory by making the binary
> smaller.
>
> > parse_url(argv[optind], &target);
> >- server.host = target.host;
> >+ server.host = xstrdup(target.host);
> > server.port = target.port;
> >+ strip_ipv6_scope(&target);
>
> Here, try this instead:
>
> parse_url(argv[optind], &target);
> server.port = target.port;
> if (ENABLE_FEATURE_IPV6) {
> server.host = xstrdup(target.host);
> strip_ipv6_scope(&target);
> } else server.host = target.host;
>
> Now you can remove the if (ENABLE) from the actual strip_ipv6_scope function,
> and it should only get called when the feature is enabled.
>
> The point of doing that is that the compiler can tell at compile time whether
> the ENABLE macro is set to 0 or 1, meaning it can do dead code elimination on
> code that can never be called, meaning the entire strip_ipv6_scope() function
> can be discarded when it's not configured in (since it's static, and therefore
> couldn't be called from outside this file), and won't take up space for
> everybody else.
Sure, this makes sense. I thought of putting a precompiler condition
around the code block, but of course the dead code elimination is much
nicer.
Below you find the patch including Rob's suggestions.
Fabian
diff --git a/networking/wget.c b/networking/wget.c
index ca3acd0..3608b90 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -340,6 +340,52 @@ static void parse_url(char *src_url, struct host_info *h)
sp = h->host;
}
+/* RFC 4007 says that the scope identifier MUST NOT be sent across the wire,
+ * unless all nodes agree on the semantic. Apache e.g. regards zone identifiers
+ * in the Host header as invalid requests, see
+ * https://issues.apache.org/bugzilla/show_bug.cgi?id=35122
+ */
+static void strip_ipv6_scope(struct host_info *h)
+{
+ char *scope, *cp;
+
+ /* Remove the IPv6 zone identifier from the host address,
+ * ugly parsing like in str2sockaddr() */
+
+ /* test if it's an IPv6 address */
+ if (h->host[0] == '[') {
+ cp = strchr(h->host, ']');
+ if (!cp || (cp[1] != ':' && cp[1] != '\0')) {
+ /* malformed address, must be [xx]:nn or [xx], dnt touch */
+ return;
+ }
+ } else {
+ cp = strrchr(h->host, ':');
+ if (cp && strchr(h->host, ':') != cp) {
+ /* more than one ':' but no port specifier, eg. "::1" */
+ cp = NULL;
+ } else {
+ /* no or only one ':' => no IPv6 address, dnt touch */
+ return;
+ }
+ }
+
+ /* as we have an IPv6 address, let's see if there is a zone identifier */
+ scope = strchr(h->host, '%');
+ if (!scope || (cp && scope > cp)) {
+ /* no scope identifier, dnt touch */
+ return;
+ }
+
+ /* remove the zone identifier */
+ if (cp) {
+ /* cp points to "]", overwrite the zone identifier with the rest */
+ overlapping_strcpy(scope, cp);
+ } else {
+ /* no port specifier, terminate at zone identifier */
+ *scope = '\0';
+ }
+}
static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/)
{
@@ -527,8 +573,13 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
#endif
parse_url(argv[optind], &target);
- server.host = target.host;
server.port = target.port;
+ if (ENABLE_FEATURE_IPV6) {
+ server.host = xstrdup(target.host);
+ strip_ipv6_scope(&target);
+ } else {
+ server.host = target.host;
+ }
/* Use the proxy if necessary */
if (use_proxy) {
More information about the busybox
mailing list