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