#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <string.h>
#include <freeradius-devel/libradius.h>
#include "std-includes.h"
#include "rfcnb-priv.h"
#include "rfcnb-util.h"
#include "rfcnb-io.h"
extern void (*Prot_Print_Routine)();
void RFCNB_CvtPad_Name(char *name1, char *name2)
{ char c, c1, c2;
int i, len;
len = strlen(name1);
for (i = 0; i < 16; i++) {
if (i >= len) {
c1 = 'C'; c2 = 'A';
} else {
c = name1[i];
c1 = (char)((int)c/16 + (int)'A');
c2 = (char)((int)c%16 + (int)'A');
}
name2[i*2] = c1;
name2[i*2+1] = c2;
}
name2[32] = 0;
}
void RFCNB_AName_To_NBName(char *AName, char *NBName)
{ char c, c1, c2;
int i;
for (i=0; i < 16; i++) {
c = AName[i];
c1 = (char)((c >> 4) + 'A');
c2 = (char)((c & 0xF) + 'A');
NBName[i*2] = c1;
NBName[i*2+1] = c2;
}
NBName[32] = 0;
}
void RFCNB_NBName_To_AName(char *NBName, char *AName)
{ char c, c1, c2;
int i;
for (i=0; i < 16; i++) {
c1 = NBName[i*2];
c2 = NBName[i*2+1];
c = (char)(((int)c1 - (int)'A') * 16 + ((int)c2 - (int)'A'));
AName[i] = c;
}
AName[i] = 0;
}
void RFCNB_Print_Hex(FILE *fd, struct RFCNB_Pkt *pkt, int Offset, int Len)
{ char c1, c2, outbuf1[33];
unsigned char c;
int i, j;
struct RFCNB_Pkt *pkt_ptr = pkt;
static char Hex_List[17] = "0123456789ABCDEF";
j = 0;
while (pkt_ptr != NULL) {
for (i = 0;
i < ((Len > (pkt_ptr -> len)?pkt_ptr -> len:Len) - Offset);
i++) {
c = pkt_ptr -> data[i + Offset];
c1 = Hex_List[c >> 4];
c2 = Hex_List[c & 0xF];
outbuf1[j++] = c1; outbuf1[j++] = c2;
if (j == 32){
outbuf1[j] = 0;
fprintf(fd, " %s\n", outbuf1);
j = 0;
}
}
Offset = 0;
Len = Len - pkt_ptr -> len;
pkt_ptr = pkt_ptr -> next;
}
if (j > 0) {
outbuf1[j] = 0;
fprintf(fd, " %s\n", outbuf1);
}
fprintf(fd, "\n");
}
struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n)
{ RFCNB_Pkt *pkt;
if ((pkt = (struct RFCNB_Pkt *)malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
RFCNB_errno = RFCNBE_NoSpace;
RFCNB_saved_errno = errno;
return(NULL);
}
pkt -> next = NULL;
pkt -> len = n;
if (n == 0) return(pkt);
if ((pkt -> data = (char *)malloc(n)) == NULL) {
RFCNB_errno = RFCNBE_NoSpace;
RFCNB_saved_errno = errno;
free(pkt);
return(NULL);
}
return(pkt);
}
int RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
{ struct RFCNB_Pkt *pkt_next; char *data_ptr;
while (pkt != NULL) {
pkt_next = pkt -> next;
data_ptr = pkt -> data;
if (data_ptr != NULL)
free(data_ptr);
free(pkt);
pkt = pkt_next;
}
}
void RFCNB_Print_Pkt(FILE *fd, char *dirn, struct RFCNB_Pkt *pkt, int len)
{ char lname[17];
fprintf(fd, "RFCNB Pkt %s:", dirn);
switch (RFCNB_Pkt_Type(pkt -> data)) {
case RFCNB_SESSION_MESSAGE:
fprintf(fd, "SESSION MESSAGE: Length = %i\n", RFCNB_Pkt_Len(pkt -> data));
RFCNB_Print_Hex(fd, pkt, RFCNB_Pkt_Hdr_Len,
#ifdef RFCNB_PRINT_DATA
RFCNB_Pkt_Len(pkt -> data) - RFCNB_Pkt_Hdr_Len
#else
40
#endif
);
if (Prot_Print_Routine != 0) {
Prot_Print_Routine(fd, strcmp(dirn, "sent"), pkt, RFCNB_Pkt_Hdr_Len,
RFCNB_Pkt_Len(pkt -> data) - RFCNB_Pkt_Hdr_Len);
}
break;
case RFCNB_SESSION_REQUEST:
fprintf(fd, "SESSION REQUEST: Length = %i\n",
RFCNB_Pkt_Len(pkt -> data));
RFCNB_NBName_To_AName((char *)(pkt -> data + RFCNB_Pkt_Called_Offset), lname);
fprintf(fd, " Called Name: %s\n", lname);
RFCNB_NBName_To_AName((char *)(pkt -> data + RFCNB_Pkt_Calling_Offset), lname);
fprintf(fd, " Calling Name: %s\n", lname);
break;
case RFCNB_SESSION_ACK:
fprintf(fd, "RFCNB SESSION ACK: Length = %i\n",
RFCNB_Pkt_Len(pkt -> data));
break;
case RFCNB_SESSION_REJ:
fprintf(fd, "RFCNB SESSION REJECT: Length = %i\n",
RFCNB_Pkt_Len(pkt -> data));
if (RFCNB_Pkt_Len(pkt -> data) < 1) {
fprintf(fd, " Protocol Error, short Reject packet!\n");
}
else {
fprintf(fd, " Error = %x\n", CVAL(pkt -> data, RFCNB_Pkt_Error_Offset));
}
break;
case RFCNB_SESSION_RETARGET:
fprintf(fd, "RFCNB SESSION RETARGET: Length = %i\n",
RFCNB_Pkt_Len(pkt -> data));
break;
case RFCNB_SESSION_KEEP_ALIVE:
fprintf(fd, "RFCNB SESSION KEEP ALIVE: Length = %i\n",
RFCNB_Pkt_Len(pkt -> data));
break;
default:
break;
}
}
int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
{
fr_ipaddr_t ipaddr;
if (ip_hton(host, AF_INET, &ipaddr) < 0) {
RFCNB_errno = RFCNBE_BadName;
RFCNB_saved_errno = errno;
return(RFCNBE_Bad);
}
memcpy(Dest_IP, &ipaddr.ipaddr.ip4addr, sizeof(struct in_addr));
return 0;
}
int RFCNB_Close(int socket)
{
close(socket);
return 0;
}
int RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
{ struct sockaddr_in Socket;
int fd;
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
RFCNB_errno = RFCNBE_BadSocket;
RFCNB_saved_errno = errno;
return(RFCNBE_Bad);
}
bzero((char *)&Socket, sizeof(Socket));
memcpy((char *)&Socket.sin_addr, (char *)&Dest_IP, sizeof(Dest_IP));
Socket.sin_port = htons(port);
Socket.sin_family = PF_INET;
if (connect(fd, (struct sockaddr *)&Socket, sizeof(Socket)) < 0) {
close(fd);
RFCNB_errno = RFCNBE_ConnectFailed;
RFCNB_saved_errno = errno;
return(RFCNBE_Bad);
}
return(fd);
}
int RFCNB_Session_Req(struct RFCNB_Con *con,
char *Called_Name,
char *Calling_Name,
BOOL *redirect,
struct in_addr *Dest_IP,
int * port)
{ char *sess_pkt;
char resp[16];
int len;
struct RFCNB_Pkt *pkt, res_pkt;
pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
if (pkt == NULL) {
return(RFCNBE_Bad);
}
sess_pkt = pkt -> data;
sess_pkt[RFCNB_Pkt_Type_Offset] = RFCNB_SESSION_REQUEST;
RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len-RFCNB_Pkt_Hdr_Len);
sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
#ifdef RFCNB_DEBUG
fprintf(stderr, "Sending packet: ");
#endif
if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
return(RFCNBE_Bad);
}
#ifdef RFCNB_DEBUG
fprintf(stderr, "Getting packet.\n");
#endif
res_pkt.data = resp;
res_pkt.len = sizeof(resp);
res_pkt.next = NULL;
if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
return(RFCNBE_Bad);
}
switch (RFCNB_Pkt_Type(resp)) {
case RFCNB_SESSION_REJ:
switch (CVAL(resp,RFCNB_Pkt_Error_Offset)) {
case 0x80:
RFCNB_errno = RFCNBE_CallRejNLOCN;
break;
case 0x81:
RFCNB_errno = RFCNBE_CallRejNLFCN;
break;
case 0x82:
RFCNB_errno = RFCNBE_CallRejCNNP;
break;
case 0x83:
RFCNB_errno = RFCNBE_CallRejInfRes;
break;
case 0x8F:
RFCNB_errno = RFCNBE_CallRejUnSpec;
break;
default:
RFCNB_errno = RFCNBE_ProtErr;
break;
}
return(RFCNBE_Bad);
break;
case RFCNB_SESSION_ACK:
return(0);
break;
case RFCNB_SESSION_RETARGET:
*redirect = TRUE;
memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
*port = SVAL(resp, RFCNB_Pkt_Port_Offset);
return(0);
break;
default:
RFCNB_errno = RFCNBE_ProtErr;
return(RFCNBE_Bad);
break;
}
}