00224 {
00225
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
00226
struct sockaddr_in *sin;
00227
struct sockaddr *sa;
00228
struct {
00229
struct rt_msghdr m_rtm;
00230
char m_space[512];
00231 } m_rtmsg;
00232
char *cp, *p = ast_strdupa(inet_ntoa(*them));
00233
int i, l,
s, seq, flags;
00234 pid_t pid = getpid();
00235
static int routeseq;
00236
00237 memset(us, 0,
sizeof(
struct in_addr));
00238
00239 memset(&m_rtmsg, 0,
sizeof(m_rtmsg));
00240 m_rtmsg.m_rtm.rtm_type = RTM_GET;
00241 m_rtmsg.m_rtm.rtm_flags = RTF_UP | RTF_HOST;
00242 m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
00243
ast_mutex_lock(&routeseq_lock);
00244 seq = ++routeseq;
00245
ast_mutex_unlock(&routeseq_lock);
00246 m_rtmsg.m_rtm.rtm_seq = seq;
00247 m_rtmsg.m_rtm.rtm_addrs = RTA_IFA | RTA_DST;
00248 m_rtmsg.m_rtm.rtm_msglen =
sizeof(
struct rt_msghdr) + sizeof(struct sockaddr_in);
00249 sin = (
struct sockaddr_in *)m_rtmsg.m_space;
00250 sin->sin_family = AF_INET;
00251 sin->sin_len =
sizeof(
struct sockaddr_in);
00252 sin->sin_addr = *them;
00253
00254
if ((
s = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
00255
ast_log(LOG_ERROR,
"Error opening routing socket\n");
00256
return -1;
00257 }
00258 flags = fcntl(s, F_GETFL);
00259 fcntl(s, F_SETFL, flags | O_NONBLOCK);
00260
if (write(s, (
char *)&m_rtmsg, m_rtmsg.m_rtm.rtm_msglen) < 0) {
00261
ast_log(LOG_ERROR,
"Error writing to routing socket: %s\n", strerror(errno));
00262 close(s);
00263
return -1;
00264 }
00265
do {
00266 l = read(s, (
char *)&m_rtmsg,
sizeof(m_rtmsg));
00267 }
while (l > 0 && (m_rtmsg.m_rtm.rtm_seq != 1 || m_rtmsg.m_rtm.rtm_pid != pid));
00268
if (l < 0) {
00269
if (errno != EAGAIN)
00270
ast_log(LOG_ERROR,
"Error reading from routing socket\n");
00271 close(s);
00272
return -1;
00273 }
00274 close(s);
00275
00276
if (m_rtmsg.m_rtm.rtm_version != RTM_VERSION) {
00277
ast_log(LOG_ERROR,
"Unsupported route socket protocol version\n");
00278
return -1;
00279 }
00280
00281
if (m_rtmsg.m_rtm.rtm_msglen != l)
00282
ast_log(LOG_WARNING,
"Message length mismatch, in packet %d, returned %d\n",
00283 m_rtmsg.m_rtm.rtm_msglen, l);
00284
00285
if (m_rtmsg.m_rtm.rtm_errno) {
00286
ast_log(LOG_ERROR,
"RTM_GET got %s (%d)\n",
00287 strerror(m_rtmsg.m_rtm.rtm_errno), m_rtmsg.m_rtm.rtm_errno);
00288
return -1;
00289 }
00290
00291 cp = (
char *)m_rtmsg.m_space;
00292
if (m_rtmsg.m_rtm.rtm_addrs)
00293
for (i = 1; i; i <<= 1)
00294
if (m_rtmsg.m_rtm.rtm_addrs & i) {
00295 sa = (
struct sockaddr *)cp;
00296
if (i == RTA_IFA && sa->sa_family == AF_INET) {
00297 sin = (
struct sockaddr_in *)sa;
00298 *us = sin->sin_addr;
00299
ast_log(LOG_DEBUG,
"Found route to %s, output from our address %s.\n", p, inet_ntoa(*us));
00300
return 0;
00301 }
00302 cp += sa->sa_len > 0 ?
00303 (1 + ((sa->sa_len - 1) | (
sizeof(
long) - 1))) :
00304
sizeof(
long);
00305 }
00306
00307
ast_log(LOG_DEBUG,
"No route found for address %s!\n", p);
00308
return -1;
00309
#else
00310
FILE *PROC;
00311
unsigned int remote_ip;
00312
int res = 1;
00313
char line[256];
00314 remote_ip = them->s_addr;
00315
00316 PROC = fopen(
"/proc/net/route",
"r");
00317
if (!PROC) {
00318 bzero(us,
sizeof(
struct in_addr));
00319
return -1;
00320 }
00321
00322 fgets(line,
sizeof(line),PROC);
00323
00324
while (!feof(PROC)) {
00325
char iface[256];
00326
unsigned int dest, gateway, mask;
00327
int i,fieldnum;
00328
char *fields[40];
00329
00330 fgets(line,
sizeof(line),PROC);
00331
00332 fieldnum = 0;
00333
for (i=0;i<
sizeof(line);i++) {
00334
char *offset;
00335
00336 fields[fieldnum++] = line + i;
00337 offset = strchr(line + i,
'\t');
00338
if (offset == NULL) {
00339
00340
break;
00341 }
else if (fieldnum >= 9) {
00342
00343
break;
00344 }
else {
00345 *offset =
'\0';
00346 i = offset - line;
00347 }
00348 }
00349
if (fieldnum >= 8) {
00350
00351 sscanf(fields[0],
"%s",iface);
00352 sscanf(fields[1],
"%x",&dest);
00353 sscanf(fields[2],
"%x",&gateway);
00354 sscanf(fields[7],
"%x",&mask);
00355
#if 0
00356
printf(
"Addr: %s %08x Dest: %08x Mask: %08x\n", inet_ntoa(*them), remote_ip, dest, mask);
00357
#endif
00358
00359
if (((remote_ip & mask) ^ dest) == 0) {
00360 res =
ast_lookup_iface(iface,us);
00361
break;
00362 }
00363 }
00364 }
00365 fclose(PROC);
00366
if (res == 1) {
00367
ast_log(LOG_WARNING,
"Yikes! No default route?!!\n");
00368 bzero(us,
sizeof(
struct in_addr));
00369
return -2;
00370 }
else if (res) {
00371
00372
return -1;
00373 }
00374
return 0;
00375
#endif
00376
}