1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
/* ip.c system IP or UDP level stuff
*
* $Id: ip.c,v 1.4 1995/03/19 17:21:06 bdale Exp $
*
* Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
* This software may be freely used, distributed, or modified, providing
* this header is not removed.
*
* Added support for Linux - Ron Atkinson N8FOW
*/
#include "ipip.h"
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netdb.h>
#include <fcntl.h>
#include <memory.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#ifndef FNDELAY
#define FNDELAY O_NDELAY
#endif
extern int errno;
#define IF_NAME "ip" /* for use with the error checking macros */
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* open and initialize the IO interface. Return -1 for error.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
int ip_open(ifp)
struct interface *ifp;
{
struct sockaddr_in ip_udpbind;
CK_IFNULL(ifp);
CK_IFTYPE2(ifp,IF_TYPE_IPIP,IF_TYPE_IPUDP);
if((ifp->status & IF_STAT_OPEN)) return 1;
if(ifp->type == IF_TYPE_IPUDP){
ifp->fd = socket(AF_INET, SOCK_DGRAM, 0);
} else {
ifp->fd = socket(AF_INET, SOCK_RAW, ifp->unit);
}
if (ifp->fd<0) {
PERR("opening socket");
return -1;
}
if (fcntl(ifp->fd, F_SETFL, FNDELAY) < 0) {
PERR("setting non-blocking I/O on raw socket");
return -1;
}
if(ifp->type == IF_TYPE_IPUDP){
(void)memset( (char *)&ip_udpbind, 0, sizeof(struct sockaddr) );
ip_udpbind.sin_addr.s_addr = INADDR_ANY;
ip_udpbind.sin_family = AF_INET;
ip_udpbind.sin_port = htons((unsigned short)ifp->unit);
if(bind(ifp->fd,(struct sockaddr *)&ip_udpbind,sizeof ip_udpbind)<0){
PERR("binding udp socket");
return -1;
}
}
ifp->status = IF_STAT_OPEN;
return 1;
}
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Read data from the specified interface. Return a complete IP datagram.
* If the datagram is not complete, then don't return anything.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
int ip_read(ifp, m)
struct interface *ifp;
struct message *m;
{
unsigned char buf[MAX_SIZE], *p;
int n, hdr_len;
unsigned int fromlen;
#ifdef LINUX
struct iphdr *ipptr;
#else
struct ip *ipptr;
#endif
struct sockaddr_in ip_from;
CK_IFNULL(ifp);
CK_IFTYPE2(ifp,IF_TYPE_IPIP,IF_TYPE_IPUDP);
CK_IFOPEN(ifp);
CK_MNULL(m);
(void)memset((char *)&ip_from, 0, sizeof(struct sockaddr));
ip_from.sin_family = AF_INET;
fromlen = sizeof ip_from;
n = recvfrom(ifp->fd, (char *)buf, MAX_SIZE, 0,(struct sockaddr *)&ip_from, &fromlen);
if(n<0){
m->length = 0;
if(errno==EINTR)return 0;
if(errno==EWOULDBLOCK)return 0;
PERR("recvfrom: on socket");
return -1;
}
if(n==0)return 0;
if(ifp->type == IF_TYPE_IPUDP){
p = buf;
} else {
#ifdef LINUX
ipptr = (struct iphdr *)buf;
hdr_len = 4 * ipptr->ihl;
#else
ipptr = (struct ip *)buf;
hdr_len = 4 * ipptr->ip_hl;
#endif
p = buf + hdr_len;
n = n - hdr_len;
}
(void)memcpy((char *)m->msg,(char *)p, n);
m->length = n;
(void)memcpy( (char *)&(m->fip), (char *)&ip_from.sin_addr, 4);
m->fport = ip_from.sin_port;
return n;
}
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* write data from to the specified interface. Return as soon as possible.
* The buffer provided will be a complete IP datagram.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
int ip_send(ifp, m)
struct interface *ifp;
struct message *m;
{
int n;
struct sockaddr_in ip_to;
CK_IFNULL(ifp);
CK_IFTYPE2(ifp,IF_TYPE_IPIP,IF_TYPE_IPUDP);
CK_IFOPEN(ifp);
CK_MNULL(m);
if(m->length<=0)return 0;
if((long)m->tip==0){
syslog(LOG_WARNING,"attempt to send to IP address 0.0.0.0");
return 0;
}
if((ifp->type==IF_TYPE_IPUDP)&&(m->tport==0)){
syslog(LOG_WARNING,"attempt to send to UDP port 0");
return 0;
}
(void)memset( (char *)&ip_to, 0, sizeof(struct sockaddr) );
ip_to.sin_family = AF_INET;
ip_to.sin_port = m->tport;
(void)memcpy((char *)&ip_to.sin_addr, (char *)&(m->tip), 4);
n = sendto(ifp->fd, (char *)m->msg, m->length, 0,
(struct sockaddr *)&ip_to, sizeof ip_to);
if(n<0){
/* Log errors but don't die, since most errors are transient */
char bugger[80];
unsigned char *p = (unsigned char *)&m->tip;
sprintf(bugger,
"ip_send(dest:%d.%d.%d.%d) sendto(): %s",
p[0], p[1], p[2], p[3], strerror (errno) ) ;
PERR(bugger);
return 0; /* Who cares? Continue. */
}
return n;
}
|