Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 21 Aug 2003 13:22:33 -0400 (EDT)
From:      Joe Marcus Clarke <marcus@FreeBSD.org>
To:        FreeBSD-gnats-submit@FreeBSD.org
Cc:        ru@FreeBSD.org
Subject:   bin/55843: [PATCH] Add Skinny support to libalias
Message-ID:  <200308211722.h7LHMX1G086528@shumai.marcuscom.com>
Resent-Message-ID: <200308211730.h7LHU0gn058484@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         55843
>Category:       bin
>Synopsis:       [PATCH] Add Skinny support to libalias
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Thu Aug 21 10:30:00 PDT 2003
>Closed-Date:
>Last-Modified:
>Originator:     Joe Marcus Clarke
>Release:        FreeBSD 4.8-STABLE i386
>Organization:
MarcusCom, Inc.
>Environment:
FreeBSD gyros.marcuscom.com 5.1-CURRENT FreeBSD 5.1-CURRENT #23: Wed Aug 20 12:27:57 EDT 2003     marcus@gyros.marcuscom.com:/usr/obj/usr/src/sys/GYROS  i386

>Description:
The attached patch adds Skinny Station Protocol support to libalias.  Skinny
is the protocol used by Cisco IP phones to talk to Cisco Call Managers.
With this code, one can use a Cisco IP phone behind a FreeBSD NAT'ing
firewall.  These diffs apply cleanly to -CURRENT and -STABLE.  I have been
running this code on both machines for about two years, and it works quite
well.

I have tried to match the style of the existing libalias code as much as
possible.
>How-To-Repeat:
	
>Fix:

	

--- libalias.diff begins here ---
diff -ruN libalias.orig/Makefile libalias/Makefile
--- src/lib/libalias.orig/Makefile	Thu Aug 21 13:01:42 2003
+++ src/lib/libalias/Makefile	Thu Aug 21 12:37:53 2003
@@ -5,7 +5,7 @@
 SHLIB_MAJOR=	4
 MAN=	libalias.3
 SRCS=	alias.c alias_cuseeme.c alias_db.c alias_ftp.c alias_irc.c \
-	alias_nbt.c alias_pptp.c alias_proxy.c alias_smedia.c \
+	alias_nbt.c alias_pptp.c alias_proxy.c alias_skinny.c alias_smedia.c \
 	alias_util.c
 INCS=	alias.h
 
diff -ruN libalias.orig/alias.c libalias/alias.c
--- src/lib/libalias.orig/alias.c	Thu Aug 21 13:01:42 2003
+++ src/lib/libalias/alias.c	Thu Aug 21 13:17:13 2003
@@ -137,6 +137,7 @@
 #define RTSP_CONTROL_PORT_NUMBER_2 7070
 #define TFTP_PORT_NUMBER 69
 #define PPTP_CONTROL_PORT_NUMBER 1723
+#define SKINNY_PORT_NUMBER 2000
 
 
 
@@ -917,6 +918,9 @@
         if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
          || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
             AliasHandlePptpIn(pip, link);
+        else if (ntohs(tc->th_dport) == SKINNY_PORT_NUMBER
+         || ntohs(tc->th_sport) == SKINNY_PORT_NUMBER)
+            AliasHandleSkinny(pip, link);
 
         alias_address = GetAliasAddress(link);
         original_address = GetOriginalAddress(link);
@@ -1098,6 +1102,9 @@
         else if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
          || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
             AliasHandlePptpOut(pip, link);
+        else if (ntohs(tc->th_sport) == SKINNY_PORT_NUMBER
+         || ntohs(tc->th_dport) == SKINNY_PORT_NUMBER)
+            AliasHandleSkinny(pip, link);
 
 /* Adjust TCP checksum since source port is being aliased */
 /* and source address is being altered                    */
diff -ruN libalias.orig/alias_db.c libalias/alias_db.c
--- src/lib/libalias.orig/alias_db.c	Thu Aug 21 13:01:42 2003
+++ src/lib/libalias/alias_db.c	Thu Aug 21 12:41:31 2003
@@ -1791,6 +1791,45 @@
     return(link);
 }
 
+struct alias_link *
+FindSkinnyOut(struct in_addr src_addr,
+              struct in_addr dst_addr,
+              u_short        src_port,
+              u_short        dst_port,
+              u_short        alias_port,
+              u_char         proto)
+{
+    int link_type;
+    struct alias_link *link;
+
+    switch (proto)
+    {
+    case IPPROTO_UDP:
+        link_type = LINK_UDP;
+        break;
+    case IPPROTO_TCP:
+        link_type = LINK_TCP;
+        break;
+    default:
+        return NULL;
+        break;
+    }
+
+    link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, 1);
+
+    if (link == NULL)
+    {
+        struct in_addr alias_addr;
+
+        alias_addr = FindAliasAddress(src_addr);
+        link = AddLink(src_addr, dst_addr, alias_addr,
+                       src_port, dst_port, alias_port,
+                       link_type);
+        link->flags |= LINK_PERMANENT;
+    }
+
+    return(link);
+}
 
 struct in_addr
 FindOriginalAddress(struct in_addr alias_addr)
diff -ruN libalias.orig/alias_local.h libalias/alias_local.h
--- src/lib/libalias.orig/alias_local.h	Thu Aug 21 13:01:42 2003
+++ src/lib/libalias/alias_local.h	Thu Aug 21 12:37:53 2003
@@ -130,6 +130,10 @@
 struct alias_link *
 	 FindRtspOut(struct in_addr _src_addr, struct in_addr _dst_addr,
 	    u_short _src_port, u_short _alias_port, u_char _proto);
+struct alias_link *
+	 FindSkinnyOut(struct in_addr _src_addr, struct in_addr _dst_addr,
+	    u_short _src_port, u_short _dst_port, u_short _alias_port, 
+	    u_char _proto);
 struct in_addr
 	 FindOriginalAddress(struct in_addr _alias_addr);
 struct in_addr
@@ -211,6 +215,9 @@
 /* CUSeeMe routines */
 void	 AliasHandleCUSeeMeOut(struct ip *_pip, struct alias_link *_link);
 void	 AliasHandleCUSeeMeIn(struct ip *_pip, struct in_addr _original_addr);
+
+/* Skinny routines */
+void	 AliasHandleSkinny(struct ip *_pip, struct alias_link *_link);
 
 /* Transparent proxy routines */
 int	 ProxyCheck(struct ip *_pip, struct in_addr *_proxy_server_addr,
diff -ruN libalias.orig/alias_skinny.c libalias/alias_skinny.c
--- src/lib/libalias.orig/alias_skinny.c	Wed Dec 31 19:00:00 1969
+++ src/lib/libalias/alias_skinny.c	Thu Aug 21 13:14:54 2003
@@ -0,0 +1,317 @@
+/*-
+ * alias_skinny.c
+ *
+ * Copyright (c) 2002 MarcusCom, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Joe Marcus Clarke <marcus@FreeBSD.org>
+ *
+ * $FreeBSD$
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <unistd.h>
+
+#include "alias_local.h"
+
+/* #define DEBUG 1 */
+
+/* XXX This needs to be dynamically setable */
+#define SKINNY_PORT_NUMBER 2000
+
+/* Message types that need translating */
+#define REG_MSG         0x00000001
+#define IP_PORT_MSG     0x00000002
+#define OPNRCVCH_ACK    0x00000022
+#define START_MEDIATX   0x0000008a
+
+struct skinny_header {
+    u_int32_t       len;
+    u_int32_t       reserved;
+    u_int32_t       msgId;
+};
+
+static u_int32_t localIpAddr = 0;
+static u_int32_t localPort = 0;
+static u_short  aliasPort = 0;
+
+struct RegisterMessage {
+    u_int32_t       msgId;
+    char            devName[16];
+    u_int32_t       uid;
+    u_int32_t       instance;
+    u_int32_t       ipAddr;
+    u_char          devType;
+    u_int32_t       maxStreams;
+};
+
+struct IpPortMessage {
+    u_int32_t       msgId;
+    u_int32_t       stationIpPort;	/* Note: Skinny uses 32-bit port
+                                     * numbers */
+};
+
+struct OpenReceiveChannelAck {
+    u_int32_t       msgId;
+    u_int32_t       status;
+    u_int32_t       ipAddr;
+    u_int32_t       port;
+    u_int32_t       passThruPartyID;
+};
+
+struct StartMediaTransmission {
+    u_int32_t       msgId;
+    u_int32_t       conferenceID;
+    u_int32_t       passThruPartyID;
+    u_int32_t       remoteIpAddr;
+    u_int32_t       remotePort;
+    u_int32_t       MSPacket;
+    u_int32_t       payloadCap;
+    u_int32_t       precedence;
+    u_int32_t       silenceSuppression;
+    u_short         maxFramesPerPacket;
+    u_int32_t       G723BitRate;
+};
+
+typedef enum {
+    ClientToServer = 0,
+    ServerToClient = 1
+} ConvDirection;
+
+
+static int
+alias_skinny_reg_msg(struct RegisterMessage *reg_msg, struct ip *pip,
+                     struct tcphdr *tc, struct alias_link *link,
+                     ConvDirection direction)
+{
+  reg_msg->ipAddr = (u_int32_t) GetAliasAddress(link).s_addr;
+
+  tc->th_sum = 0;
+  tc->th_sum = TcpChecksum(pip);
+
+  return 0;
+}
+
+static int
+alias_skinny_startmedia(struct StartMediaTransmission *start_media,
+                        struct ip *pip, struct tcphdr *tc,
+                        struct alias_link *link, ConvDirection direction)
+{
+  struct in_addr  dst, src;
+
+  dst.s_addr = start_media->remoteIpAddr;
+  src.s_addr = localIpAddr;
+
+  /* XXX I should probably handle in bound global translations as well. */
+
+  return 0;
+}
+
+static int
+alias_skinny_port_msg(struct IpPortMessage *port_msg, struct ip *pip,
+                      struct tcphdr *tc, struct alias_link *link,
+                      ConvDirection direction)
+{
+  port_msg->stationIpPort = (u_int32_t) ntohs(GetAliasPort(link));
+
+  tc->th_sum = 0;
+  tc->th_sum = TcpChecksum(pip);
+
+  return 0;
+}
+
+static int
+alias_skinny_opnrcvch_ack(struct OpenReceiveChannelAck *opnrcvch_ack,
+                          struct ip * pip, struct tcphdr *tc, 
+                          struct alias_link *link, ConvDirection direction)
+{
+  struct in_addr  null_addr;
+  struct alias_link *opnrcv_link;
+
+  localIpAddr = opnrcvch_ack->ipAddr;
+  localPort = opnrcvch_ack->port;
+
+  null_addr.s_addr = INADDR_ANY;
+  aliasPort = FindNewPortGroup(null_addr, FindAliasAddress(pip->ip_src),
+                               htons((u_short) opnrcvch_ack->port),
+                               0, 1, IPPROTO_UDP, 1);
+  opnrcv_link = FindSkinnyOut(pip->ip_src, null_addr,
+                              htons((u_short) opnrcvch_ack->port), 0,
+                              aliasPort, IPPROTO_UDP);
+  opnrcvch_ack->ipAddr = (u_int32_t) GetAliasAddress(link).s_addr;
+  opnrcvch_ack->port = (u_int32_t) ntohs(aliasPort);
+
+  tc->th_sum = 0;
+  tc->th_sum = TcpChecksum(pip);
+
+  return 0;
+}
+
+void
+AliasHandleSkinny(struct ip *pip, struct alias_link *link)
+{
+  int             hlen, tlen, dlen;
+  struct tcphdr  *tc;
+  u_int32_t       msgId, len, t;
+  struct skinny_header *sd;
+  int             orig_len, skinny_hdr_len = sizeof(struct skinny_header);
+  ConvDirection   direction;
+
+  tc = (struct tcphdr *) ((char *)pip + (pip->ip_hl << 2));
+  hlen = (pip->ip_hl + tc->th_off) << 2;
+  tlen = ntohs(pip->ip_len);
+  dlen = tlen - hlen;
+
+  sd = (struct skinny_header *) ((char *)pip + hlen);
+
+  /*
+   * XXX This direction is reserved for future use.  I still need to
+   * handle the scenario where the call manager is on the inside, and
+   * the calling phone is one the global outside.
+   */
+  if (ntohs(tc->th_dport) == SKINNY_PORT_NUMBER) {
+    direction = ClientToServer;
+  } else if (ntohs(tc->th_sport) == SKINNY_PORT_NUMBER) {
+    direction = ServerToClient;
+  } else {
+#ifdef DEBUG
+    fprintf(stderr,
+            "PacketAlias/Skinny: Invalid port number, not a Skinny packet\n");
+#endif
+    return;
+  }
+
+  orig_len = dlen;
+  /*
+   * Skinny packets can contain many messages.  We need to loop through
+   * the packet using len to determine message boundaries.  This comes
+   * into play big time with port messages being in the same packet as
+   * register messages.  Also, open receive channel acks are
+   * usually buried in a pakcet some 400 bytes long.
+   */
+  while (dlen >= skinny_hdr_len) {
+    len = (sd->len);
+    msgId = (sd->msgId);
+    t = len;
+
+    if (t < 0 || t > orig_len || t > dlen) {
+#ifdef DEBUG
+      fprintf(stderr,
+              "PacketAlias/Skinny: Not a skinny packet, invalid length \n");
+#endif
+      return;
+    }
+    switch (msgId) {
+      case REG_MSG:
+        {
+          struct RegisterMessage *reg_mesg;
+
+          if (len < sizeof(struct RegisterMessage)) {
+#ifdef DEBUG
+            fprintf(stderr,
+                    "PacketAlias/Skinny: Not a skinny packet, bad registration message\n");
+#endif
+            return;
+          }
+          reg_mesg = (struct RegisterMessage *) & sd->msgId;
+#ifdef DEBUG
+          fprintf(stderr,
+                  "PacketAlias/Skinny: Received a register message");
+#endif
+	  alias_skinny_reg_msg(reg_mesg, pip, tc, link, direction);
+        }
+        break;
+      case IP_PORT_MSG:
+        {
+          struct IpPortMessage *port_mesg;
+          if (len < sizeof(struct IpPortMessage)) {
+#ifdef DEBUG
+            fprintf(stderr,
+                    "PacketAlias/Skinny: Not a skinny packet, port message\n");
+#endif
+            return;
+          }
+#ifdef DEBUG
+          fprintf(stderr
+                  "PacketAlias/Skinny: Received ipport message\n");
+#endif
+          port_mesg = (struct IpPortMessage *) & sd->msgId;
+          alias_skinny_port_msg(port_mesg, pip, tc, link, direction);
+        }
+        break;
+      case OPNRCVCH_ACK:
+        {
+          struct OpenReceiveChannelAck *opnrcvchn_ack;
+
+          if (len < sizeof(struct OpenReceiveChannelAck)) {
+#ifdef DEBUG
+            fprintf(stderr,
+                    "PacketAlias/Skinny: Not a skinny packet, packet,OpnRcvChnAckMsg\n");
+#endif
+            return;
+          }
+#ifdef DEBUG
+          fprintf(stderr,
+                  "PacketAlias/Skinny: Received open rcv channel msg\n");
+#endif
+          opnrcvchn_ack = (struct OpenReceiveChannelAck *) & sd->msgId;
+          alias_skinny_opnrcvch_ack(opnrcvchn_ack, pip, tc, link, direction);
+        }
+        break;
+      case START_MEDIATX:
+        {
+          struct StartMediaTransmission *startmedia_tx;
+
+          if (len < sizeof(struct StartMediaTransmission)) {
+#ifdef DEBUG
+            fprintf(stderr,
+                    "PacketAlias/Skinny: Not a skinny packet,StartMediaTx Message\n");
+#endif
+            return;
+          }
+#ifdef DEBUG
+          fprintf(stderr,
+                  "PacketAlias/Skinny: Received start media trans msg\n");
+#endif
+           startmedia_tx = (struct StartMediaTransmission *) & sd->msgId;
+           alias_skinny_startmedia(startmedia_tx, pip, tc, link, direction);
+         }
+         break;
+       default:
+         break;
+     }
+     /* Place the pointer at the next message in the packet. */
+     dlen -= len + (skinny_hdr_len - sizeof(msgId));
+     sd = (struct skinny_header *) (((char *)&sd->msgId) + len);
+   }
+}
--- libalias.diff ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200308211722.h7LHMX1G086528>