From: Ken Raeburn Date: Tue, 12 Mar 2002 03:00:08 +0000 (+0000) Subject: Handle IPv6 sockets that are used to communicate over IPv4, and permit use of X-Git-Tag: krb5-1.3-alpha1~835 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=b90ed64cbbb82265fa19561ba0b8bb3e64241d83;p=krb5.git Handle IPv6 sockets that are used to communicate over IPv4, and permit use of non-IPv4 addresses if address checking is turned off. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@14260 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/krb4/ChangeLog b/src/lib/krb4/ChangeLog index 881f09fb1..2072e45de 100644 --- a/src/lib/krb4/ChangeLog +++ b/src/lib/krb4/ChangeLog @@ -1,3 +1,21 @@ +2002-03-11 Ken Raeburn + + Handle IPv6 sockets that are used to communicate over IPv4, and + permit use of non-IPv4 addresses if address checking is turned + off: + * mk_priv.c (krb4int_address_less): New function. Compares IPv4 + addresses for ordering, but also handles the IPv6 v4-mapped form. + (krb_mk_priv): Use krb4int_address_less. Handle sender/receiver + addresses that are IPv6 v4-mapped like IPv4 addresses, or store + zero for other addresses. + * mk_safe.c (krb_mk_safe): Use krb4int_address_less. Handle + sender/receiver addresses that are IPv6 v4-mapped like IPv4 + addresses, or store zero for other addresses. + * rd_priv.c (krb_rd_priv): Use krb4int_address_less. Deal with + socket addresses that are v4-mapped IPv6 addresses. + * rd_safe.c (krb_rd_safe): Use krb4int_address_less. Deal with + socket addresses that are v4-mapped IPv6 addresses. + 2001-10-09 Ken Raeburn * cr_tkt.c, decomp_tkt.c, g_in_tkt.c, tf_util.c: Make prototypes diff --git a/src/lib/krb4/mk_priv.c b/src/lib/krb4/mk_priv.c index bc9f9bcf1..41a1a708f 100644 --- a/src/lib/krb4/mk_priv.c +++ b/src/lib/krb4/mk_priv.c @@ -93,6 +93,72 @@ extern int krb_debug; #endif */ +/* Utility function: + + Determine order of addresses, if SENDER less than RECEIVER return 1 + so caller will negate timestamp. Return -1 for failure. */ +int +krb4int_address_less (struct sockaddr_in *sender, struct sockaddr_in *receiver) +{ + unsigned long sender_addr, receiver_addr; + unsigned short sender_port, receiver_port; + switch (sender->sin_family) { + case AF_INET: + sender_addr = sender->sin_addr.s_addr; + sender_port = sender->sin_port; + break; +#ifdef KRB5_USE_INET6 + case AF_INET6: + struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sender; + if (IN6_IS_ADDR_V4MAPPED (s6)) { + struct sockaddr_in sintmp = { 0 }; + memcpy (&sintmp.sin_addr.s_addr, + 12+(char*)&s6->sin6_addr.s6_addr, + 4); + sender_addr = sintmp.sin_addr.s_addr; + } else + return -1; + sender_port = s6->sin6_port; + break; +#endif + default: + return -1; + } + switch (receiver->sin_family) { + case AF_INET: + receiver_addr = receiver->sin_addr.s_addr; + receiver_port = receiver->sin_port; + break; +#ifdef KRB5_USE_INET6 + case AF_INET6: + struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) receiver; + if (IN6_IS_ADDR_V4MAPPED (s6)) { + struct sockaddr_in sintmp = { 0 }; + memcpy (&sintmp.sin_addr.s_addr, + 12+(char*)&s6->sin6_addr.s6_addr, + 4); + receiver_addr = sintmp.sin_addr.s_addr; + } else + return -1; + receiver_port = s6->sin6_port; + break; +#endif + default: + return -1; + } + /* For compatibility with broken old code, compares are done in + VAX byte order (LSBFIRST). */ + if (lsb_net_ulong_less(sender_addr, receiver_addr) == -1 + || (lsb_net_ulong_less(sender_addr, receiver_addr) == 0 + && lsb_net_ushort_less(sender_port, receiver_port) == -1)) + return 1; + return 0; + /* + * all that for one tiny bit! Heaven help those that talk to + * themselves. + */ +} + long KRB5_CALLCONV krb_mk_priv(in, out, length, schedule, key, sender, receiver) u_char *in; /* application data */ @@ -155,24 +221,33 @@ krb_mk_priv(in, out, length, schedule, key, sender, receiver) *p++ = msg_time_5ms; /* stuff source address */ - memcpy(p, &sender->sin_addr.s_addr, - sizeof(sender->sin_addr.s_addr)); + if (sender->sin_family == AF_INET) + memcpy(p, &sender->sin_addr.s_addr, sizeof(sender->sin_addr.s_addr)); +#ifdef KRB5_USE_INET6 + else if (sender->sin_family == AF_INET6 + && IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)sender)->sin6_addr)) + memcpy(p, 12+(char*)&((struct sockaddr_in6 *)sender)->sin6_addr, 4); +#endif + else + /* The address isn't one we can encode in 4 bytes -- but + that's okay if the receiver doesn't care. */ + memset(p, 0, 4); p += sizeof(sender->sin_addr.s_addr); /* * direction bit is the sign bit of the timestamp. Ok * until 2038?? */ - /* For compatibility with broken old code, compares are done in VAX - byte order (LSBFIRST) */ - if (lsb_net_ulong_less(sender->sin_addr.s_addr, /* src < recv */ - receiver->sin_addr.s_addr) == -1) - msg_time_sec = -msg_time_sec; - else if (lsb_net_ulong_less(sender->sin_addr.s_addr, - receiver->sin_addr.s_addr) == 0) - if (lsb_net_ushort_less(sender->sin_port, - receiver->sin_port) == -1) - msg_time_sec = -msg_time_sec; + switch (krb4int_address_less (sender, receiver)) { + case 1: + msg_time_sec = -msg_time_sec; + break; + case -1: + /* Which way should we go in this case? */ + case 0: + break; + } + /* stuff time sec */ KRB4_PUT32BE(p, msg_time_sec); diff --git a/src/lib/krb4/mk_safe.c b/src/lib/krb4/mk_safe.c index f4bb0a660..b797a6a85 100644 --- a/src/lib/krb4/mk_safe.c +++ b/src/lib/krb4/mk_safe.c @@ -127,29 +127,25 @@ krb_mk_safe(in, out, length, key, sender, receiver) *p++ = msg_time_5ms; /* stuff source address */ - memcpy(p, &sender->sin_addr.s_addr, - sizeof(sender->sin_addr.s_addr)); + if (sender->sin_family == AF_INET) + memcpy(p, &sender->sin_addr.s_addr, sizeof(sender->sin_addr.s_addr)); +#ifdef KRB5_USE_INET6 + else if (sender->sin_family == AF_INET6 + && IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)sender)->sin6_addr)) + memcpy(p, 12+(char*)&((struct sockaddr_in6 *)sender)->sin6_addr, 4); +#endif + else + /* The address isn't one we can encode in 4 bytes -- but + that's okay if the receiver doesn't care. */ + memset(p, 0, 4); p += sizeof(sender->sin_addr.s_addr); /* * direction bit is the sign bit of the timestamp. Ok until * 2038?? */ - /* For compatibility with broken old code, compares are done in VAX - byte order (LSBFIRST) */ - if (lsb_net_ulong_less(sender->sin_addr.s_addr, /* src < recv */ - receiver->sin_addr.s_addr) == -1) - msg_time_sec = -msg_time_sec; - else if (lsb_net_ulong_less(sender->sin_addr.s_addr, - receiver->sin_addr.s_addr) == 0) - if (lsb_net_ushort_less(sender->sin_port, - receiver->sin_port) == -1) - msg_time_sec = -msg_time_sec; - /* - * all that for one tiny bit! Heaven help those that talk to - * themselves. - */ - + if (krb4int_address_less (sender, receiver) == 1) + msg_time_sec = -msg_time_sec; /* stuff time sec */ KRB4_PUT32BE(p, msg_time_sec); diff --git a/src/lib/krb4/rd_priv.c b/src/lib/krb4/rd_priv.c index e7b42a0fa..6fcce6205 100644 --- a/src/lib/krb4/rd_priv.c +++ b/src/lib/krb4/rd_priv.c @@ -154,9 +154,26 @@ krb_rd_priv(in, in_length, schedule, key, sender, receiver, m_data) /* don't swap, net order always */ p += sizeof(src_addr.s_addr); - if (!krb_ignore_ip_address - && src_addr.s_addr != sender->sin_addr.s_addr) - return RD_AP_MODIFIED; + if (!krb_ignore_ip_address) { + switch (sender->sin_family) { + case AF_INET: + if (src_addr.s_addr != sender->sin_addr.s_addr) + return RD_AP_MODIFIED; + break; +#ifdef KRB5_USE_INET6 + case AF_INET6: + if (IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)sender)->sin6_addr) + && !memcmp (&src_addr.s_addr, + 12 + (char *) &((struct sockaddr_in6 *)sender)->sin6_addr, + 4)) + break; + /* Not v4 mapped? Not ignoring addresses? You lose. */ + return RD_AP_MODIFIED; +#endif + default: + return RD_AP_MODIFIED; + } + } /* safely get time_sec */ KRB4_GET32(m_data->time_sec, p, le); @@ -169,31 +186,26 @@ krb_rd_priv(in, in_length, schedule, key, sender, receiver, m_data) back to the receiver, but most higher level protocols can deal with that more directly. */ if (krb_ignore_ip_address) { - if (m_data->time_sec < 0) - m_data->time_sec = -m_data->time_sec; - } else if (lsb_net_ulong_less(sender->sin_addr.s_addr, - receiver->sin_addr.s_addr) == -1) - /* src < recv */ - m_data->time_sec = -m_data->time_sec; - else if (lsb_net_ulong_less(sender->sin_addr.s_addr, - receiver->sin_addr.s_addr) == 0) - if (lsb_net_ushort_less(sender->sin_port, - receiver->sin_port) == -1) - /* src < recv */ + if (m_data->time_sec < 0) m_data->time_sec = -m_data->time_sec; - /* - * all that for one tiny bit! - * Heaven help those that talk to themselves. - */ + } else + switch (krb4int_address_less (sender, receiver)) { + case 1: + m_data->time_sec = -m_data->time_sec; + break; + case -1: + if (m_data->time_sec < 0) + m_data->time_sec = -m_data->time_sec; + break; + } /* check the time integrity of the msg */ t_local = TIME_GMT_UNIXSEC; delta_t = t_local - m_data->time_sec; if (delta_t < 0) delta_t = -delta_t; /* Absolute value of difference */ - if (delta_t > CLOCK_SKEW) { + if (delta_t > CLOCK_SKEW) return RD_AP_TIME; /* XXX should probably be better code */ - } DEB(("\ndelta_t = %d", delta_t)); /* diff --git a/src/lib/krb4/rd_safe.c b/src/lib/krb4/rd_safe.c index 40766ba52..f3cc584c1 100644 --- a/src/lib/krb4/rd_safe.c +++ b/src/lib/krb4/rd_safe.c @@ -124,9 +124,26 @@ krb_rd_safe(in,in_length,key,sender,receiver,m_data) /* don't swap, net order always */ p += sizeof(src_addr.s_addr); - if (!krb_ignore_ip_address - && src_addr.s_addr != sender->sin_addr.s_addr) - return RD_AP_MODIFIED; + if (!krb_ignore_ip_address) { + switch (sender->sin_family) { + case AF_INET: + if (src_addr.s_addr != sender->sin_addr.s_addr) + return RD_AP_MODIFIED; + break; +#ifdef KRB5_USE_INET6 + case AF_INET6: + if (IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)sender)->sin6_addr) + && !memcmp (&src_addr.s_addr, + 12 + (char *) &((struct sockaddr_in6 *)sender)->sin6_addr, + 4)) + break; + /* Not v4 mapped? Not ignoring addresses? You lose. */ + return RD_AP_MODIFIED; +#endif + default: + return RD_AP_MODIFIED; + } + } /* safely get time_sec */ KRB4_GET32(m_data->time_sec, p, le); @@ -139,22 +156,18 @@ krb_rd_safe(in,in_length,key,sender,receiver,m_data) back to the receiver, but most higher level protocols can deal with that more directly. */ if (krb_ignore_ip_address) { - if (m_data->time_sec <0) - m_data->time_sec = -m_data->time_sec; - } else if (lsb_net_ulong_less(sender->sin_addr.s_addr, - receiver->sin_addr.s_addr)==-1) - /* src < recv */ - m_data->time_sec = - m_data->time_sec; - else if (lsb_net_ulong_less(sender->sin_addr.s_addr, - receiver->sin_addr.s_addr)==0) - if (lsb_net_ushort_less(sender->sin_port,receiver->sin_port)==-1) - /* src < recv */ - m_data->time_sec = - m_data->time_sec; - - /* - * All that for one tiny bit! Heaven help those that talk to - * themselves. - */ + if (m_data->time_sec < 0) + m_data->time_sec = -m_data->time_sec; + } else + switch (krb4int_address_less (sender, receiver)) { + case 1: + m_data->time_sec = -m_data->time_sec; + break; + case -1: + if (m_data->time_sec < 0) + m_data->time_sec = -m_data->time_sec; + break; + } /* check the time integrity of the msg */ t_local = TIME_GMT_UNIXSEC;