On Thu, Mar 15, 2001 at 11:51:02AM -0800, Guy Harris wrote:
> > In pcap-snoop.c:
> > #ifdef SIOCGIFMTU
> > /*
> > * XXX - IRIX appears to give you an error if you try to set the
> > * capture length to be greater than the MTU, so let's try to get
> > * the MTU first and, if that succeeds, trim the snap length
> > * to be no greater than the MTU.
> > */
> > (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
> > if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) {
> > snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCGIFMTU: %s",
> > pcap_strerror(errno));
> > goto bad;
> > }
> >
> > Works fine with 6.5 but not 6.2
>
> ...
>
> > According to 6.2, SIOCGIFMTU is an invalid operation on the socket.
>
> Does that mean that
>
> 1) SIOCGIFMTU isn't defined
>
It could also mean that this ioctl is defined but not supported by kernel
(openBSD 2.6 and prior, MacOS and some others), we hit this rock with snort
as well, and attached is the piece which we use to obtain MTU on the systems
where SIOCIFMTU is not available, if interested. Probably isn't 100% portable too...
/*
* sample piece to retrieve MTU of an interface if SIOCGIFMTU is not available.
* Thanks to Angelos D. Keromytis of OpenBSD for pointers.
*
*
* [EMAIL PROTECTED] Fri Feb 9 05:49:31 ICT 2001
* Compile as:
* gcc open_getmtu.c -o open_getmtu
* su
* ./open_getmtu interface
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#ifndef ETHERNET_MTU
#define ETHERNET_MTU 1500
#endif
#define DEBUG
extern int errno;
void PrintError(char *msg) {
fprintf(stderr,"%s: %s\n", msg, strerror(errno));
}
int GetIfrMTU(char *name) {
int retval;
int fd, rd, n;
struct ifreq ifr;
struct sockaddr_in local, remote, *sin;
struct rt_msghdr *rtm;
retval = ETHERNET_MTU; /* to make ourselves fail-proof, we will return default
ETHERNET_MTU fail */
fd = socket(AF_INET, SOCK_DGRAM, 0);
if ( fd < 0) {
PrintError("socket");
return -1; /* something serious got screwed up */
}
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
/* get IP address of other end of P-t-P link or broadcast
address in the subnet */
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
/* failed to obtain interface flags.. no go */
close(fd);
return -1; /* can not get flags.. something is bad */
}
if (ifr.ifr_flags & IFF_POINTOPOINT) {
/* if p-t-p we will use IP address of remote end... */
if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0) {
close(fd);
return retval;
}
bcopy((void *)&ifr.ifr_dstaddr,(void *)&remote, sizeof(remote));
} else {
/* otherwise we just get broadcast */
if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0) {
/* no broadcast and no p-t-p? */
close(fd);
return retval;
}
bcopy((void *)&ifr.ifr_broadaddr,(void *)&remote, sizeof(remote));
} /* if p-t-p */
if (remote.sin_family != AF_INET) {
/* if not AF_INET, then we'll very likely fail bellow.. */
close(fd);
return retval;
}
#ifdef DEBUG
printf("GetIfrMTU: remote address is: %s\n", inet_ntoa(remote.sin_addr));
#endif
if ((rd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
/* failed to create route socket, just return default */
close(fd);
return retval;
}
#ifdef DEBUG
printf("Routing socket created\n");
#endif
/* now issue RTM_GET for IP address (RTM_RESOLVE doesn't work?) */
rtm = (struct rt_msghdr *) calloc(1, (sizeof(struct rt_msghdr) + 512)); /* a'la
UNP/R.Stevens */
if (rtm == NULL) {
PrintError("calloc");
close(fd);
close(rd);
return retval;
}
rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in);
rtm->rtm_version = RTM_VERSION;
rtm->rtm_type = RTM_GET;
rtm->rtm_addrs = RTA_DST;
rtm->rtm_pid = getpid();
rtm->rtm_seq = 1234; /* random */
sin = (struct sockaddr_in *)(rtm + 1);
bcopy((void *)&remote, (void *) sin, sizeof(sin));
sin->sin_len = sizeof(struct sockaddr_in);
if (write(rd, rtm, rtm->rtm_msglen) != rtm->rtm_msglen) {
/* something is wrong . .. */
PrintError("write");
free(rtm);
close(fd);
close(rd);
return retval;
}
do {
n = read(rd, rtm, sizeof(struct rt_msghdr) + 512);
if (n < 0) {
free(rtm);
close(fd);
close(rd);
return retval;
}
} while (rtm->rtm_type !=RTM_GET || rtm->rtm_seq != 1234
|| rtm->rtm_pid != getpid());
retval = rtm->rtm_rmx.rmx_mtu;
free(rtm);
close(fd);
close(rd);
return retval;
}
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr,"usage %s interface\n", argv[0]);
return 1;
}
printf(" %s MTU is %i\n", argv[1], GetIfrMTU(argv[1]));
return 0;
}