From owner-freebsd-bugs@FreeBSD.ORG Thu Aug 21 10:30:02 2003 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id EF70516A4BF for ; Thu, 21 Aug 2003 10:30:02 -0700 (PDT) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id EB72943FDD for ; Thu, 21 Aug 2003 10:30:00 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.12.9/8.12.9) with ESMTP id h7LHU0Up058485 for ; Thu, 21 Aug 2003 10:30:00 -0700 (PDT) (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.9/8.12.9/Submit) id h7LHU0gn058484; Thu, 21 Aug 2003 10:30:00 -0700 (PDT) Resent-Date: Thu, 21 Aug 2003 10:30:00 -0700 (PDT) Resent-Message-Id: <200308211730.h7LHU0gn058484@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Joe Marcus Clarke Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 1DC7216A4BF; Thu, 21 Aug 2003 10:22:38 -0700 (PDT) Received: from shumai.marcuscom.com (rdu57-17-158.nc.rr.com [66.57.17.158]) by mx1.FreeBSD.org (Postfix) with ESMTP id E2D7343F85; Thu, 21 Aug 2003 10:22:34 -0700 (PDT) (envelope-from marcus@shumai.marcuscom.com) Received: from shumai.marcuscom.com (localhost.marcuscom.com [127.0.0.1]) by shumai.marcuscom.com (8.12.9/8.12.9) with ESMTP id h7LHMXXE086529; Thu, 21 Aug 2003 13:22:33 -0400 (EDT) (envelope-from marcus@shumai.marcuscom.com) Received: (from marcus@localhost) by shumai.marcuscom.com (8.12.9/8.12.9/Submit) id h7LHMX1G086528; Thu, 21 Aug 2003 13:22:33 -0400 (EDT) Message-Id: <200308211722.h7LHMX1G086528@shumai.marcuscom.com> Date: Thu, 21 Aug 2003 13:22:33 -0400 (EDT) From: Joe Marcus Clarke To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 cc: ru@FreeBSD.org Subject: bin/55843: [PATCH] Add Skinny support to libalias X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: Joe Marcus Clarke List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Aug 2003 17:30:03 -0000 >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 + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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: