Handle IPv6 sockets that are used to communicate over IPv4, and permit use of
authorKen Raeburn <raeburn@mit.edu>
Tue, 12 Mar 2002 03:00:08 +0000 (03:00 +0000)
committerKen Raeburn <raeburn@mit.edu>
Tue, 12 Mar 2002 03:00:08 +0000 (03:00 +0000)
non-IPv4 addresses if address checking is turned off.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@14260 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb4/ChangeLog
src/lib/krb4/mk_priv.c
src/lib/krb4/mk_safe.c
src/lib/krb4/rd_priv.c
src/lib/krb4/rd_safe.c

index 881f09fb1594f4cd66735ba08463140c23622ca0..2072e45de0e5f1e7bfbc7092d18d9cafd4d5f5c0 100644 (file)
@@ -1,3 +1,21 @@
+2002-03-11  Ken Raeburn  <raeburn@mit.edu>
+
+       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  <raeburn@mit.edu>
 
        * cr_tkt.c, decomp_tkt.c, g_in_tkt.c, tf_util.c: Make prototypes
index bc9f9bcf11a234d6c9344ce498fb79c951722db8..41a1a708fd04b020b734d2a2b8455326ea4db50f 100644 (file)
@@ -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);
 
index f4bb0a66009fd3de9f71e21a3052eaf270ca38cc..b797a6a856cd63a63b1cde6b45dc9dd828c3b3c6 100644 (file)
@@ -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);
 
index e7b42a0faf4bb7b233c915e7b4bf25c9f3a2563b..6fcce62050a89d6c5dde261b0f118c3fd905ac37 100644 (file)
@@ -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));
 
     /*
index 40766ba523069709173b3fb7e20e2e04b51ed674..f3cc584c1147247cef277e8815441fc40f27d88e 100644 (file)
@@ -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;