Big Stack Routing

I have been trying to code a short program (see below) to set the
default route on the big stack using routing sockets but to no avail. It
fails on the write to the socket but I can’t see why. Please could someone
point me to what I am doing wrong.
I am logged in as root and the program is chmodded to a+s with root
owner and group in case there is any confusion as to whether it is being run
as superuser or not.

Thanks in advance

Poseidon

#include <stdio.h>
#include <sys/ioctl.h>
#include <net/if_dl.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/route.h>
#include <net/if.h>

struct {
struct rt_msghdr m_rtm;
char m_space[512]; // leave enough space for the sockaddr’s
} m_rtmsg;

#define rtm m_rtmsg.m_rtm
int rtm_seq = 0;
int len;

int main(int argc, char *argv[])
{
int rtsk;
struct sockaddr_in *rtdst;
struct sockaddr_in *rtgat;
struct sockaddr_in *rtnet;
register unsigned char *cp = m_rtmsg.m_space;
int result;

memset(&m_rtmsg,0x00, sizeof(m_rtmsg)); // zero message area
rtm.rtm_version = RTM_VERSION;
rtm.rtm_type = RTM_CHANGE; // RTM_ADD also fails write
rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
rtm.rtm_pid = getpid();
rtm.rtm_seq = ++rtm_seq;

/* set up sockaddrs in order of addr flags from lsb up, that means DST,
followed by GATEWAY followed by NETMASK
*/
rtdst = (struct sockaddr_in *)cp; // rtdst points to start of m_space
rtdst->sin_len = sizeof(*rtdst); // it’s address is 0.0.0.0 since
rtdst->sin_family = AF_INET; // m_space has been zeroed
cp += sizeof(*rtdst); // point cp to after dst
sockaddr
rtgat = (struct sockaddr_in *)cp; // rtgat is next in m_space
rtgat->sin_len = sizeof(*rtgat);
rtgat->sin_family = AF_INET; // address is from command line
if (inet_aton(argv[1],&(rtgat->sin_addr))==0) { // 0 if error occurs
printf(“failure\n”);
return -1;
}
cp += sizeof(*rtgat); // advance cp to after gateway
rtnet = (struct sockaddr_in *)cp; // rtnet is next in m_space
rtnet->sin_len = sizeof(*rtnet); // address is 0.0.0.0 as m_space
rtnet->sin_family = AF_INET; // has been cleared
cp += sizeof(*rtnet); // advance cp to after netmask

rtm.rtm_msglen = len = cp - (unsigned char*)&m_rtmsg;

if ((rtsk = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
printf(“no route socket\n”);
return -1;
}

// result always returns -1 here.
if ((result = write(rtsk, (char *)&m_rtmsg, len)) < len) {
printf(“no write to route socket, result: %d\n”,result);
return -1;
}
}

Does nobody know how to set routes with a routing socket for the big stack
(RTP 6.1A)? No matter what I do with the above code (see previous post), it
always comes back with a failed write. Sean, if you are out there, please
take a look to see what I am doing wrong, or even better, just paste some
code from something that you know works (like netmanager).

regards

Poseidon

P.S. In the course of my investigations, I have managed to read from a
routing socket. I first write (RTM_GET) a blank DST, NETMASK and IFP(type
AF_LINK). The addr bits of the corresponding read tell me I’m getting DST,
GATEWAY, NETMASK and IFP sockaddrs in the message. What I actually seem to
get is DST, GATEWAY, IFP, GATEWAY and although the first gateway sockaddr
claims to be 16 bytes long it actually takes 20 bytes, thus screwing up my
message disassembly.

Should I be posting to a different group with questions about routing
sockets?

Poseidon

Still no luck :slight_smile: Been a little swamped lately. Will try to dig up
an example soon.

-seanb

Poseidon <paul.ryan2@nospam.virgin.net> wrote:
: Should I be posting to a different group with questions about routing
: sockets?

: Poseidon

Thanks Sean.

Your code works for me. You might want to print out errno
to see why it’s failing. Here’s the version I did, but basically the
same thing.

-seanb



#include <sys/socket.h>
#include <sys/uio.h>
#include <unistd.h>
#include <net/route.h>
#include <netinet/in.h>
#include <stdio.h>
#include <libgen.h>
#include <arpa/inet.h>
#include <process.h>
#include <errno.h>

struct my_rt {
struct rt_msghdr rt;
struct sockaddr_in dst;
struct sockaddr_in gate;
struct sockaddr_in mask;
};

int
main(int argc, char **argv)
{
int s;
struct rt_msghdr *rtm;
struct sockaddr_in *dst, *gate, *mask;
struct my_rt my_rt;

if(argc < 2) {
fprintf(stderr, “Usage: %s: <ip_addr_of_default_gateway>\n”, basename(argv[0]));
return 1;
}

if((s = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
perror(“socket”);
return 1;
}

memset(&my_rt, 0x00, sizeof(my_rt));

rtm = &my_rt.rt;

dst = &my_rt.dst;
gate = &my_rt.gate;
mask = &my_rt.mask;

rtm->rtm_type = RTM_ADD;
rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
rtm->rtm_msglen = sizeof(my_rt);
rtm->rtm_version = RTM_VERSION;
rtm->rtm_seq = 1234;
rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
rtm->rtm_pid = getpid();

dst->sin_len = sizeof(*dst);
dst->sin_family = AF_INET;

mask->sin_len = sizeof(*mask);
mask->sin_family = AF_INET;

gate->sin_len = sizeof(*gate);
gate->sin_family = AF_INET;
inet_aton(argv[1], &gate->sin_addr);

AGAIN:
if(write(s, rtm, rtm->rtm_msglen) < 0) {

if(errno == EEXIST && rtm->rtm_type == RTM_ADD) {
rtm->rtm_type = RTM_CHANGE;
goto AGAIN;
}
perror(“write”);
return 1;
}

return 0;
}


Poseidon <paul.ryan2@nospam.virgin.net> wrote:
: I have been trying to code a short program (see below) to set the
: default route on the big stack using routing sockets but to no avail. It
: fails on the write to the socket but I can’t see why. Please could someone
: point me to what I am doing wrong.
: I am logged in as root and the program is chmodded to a+s with root
: owner and group in case there is any confusion as to whether it is being run
: as superuser or not.

: Thanks in advance

: Poseidon

: #include <stdio.h>
: #include <sys/ioctl.h>
: #include <net/if_dl.h>
: #include <errno.h>
: #include <netinet/in.h>
: #include <arpa/inet.h>
: #include <sys/socket.h>
: #include <net/route.h>
: #include <net/if.h>

: struct {
: struct rt_msghdr m_rtm;
: char m_space[512]; // leave enough space for the sockaddr’s
: } m_rtmsg;

: #define rtm m_rtmsg.m_rtm
: int rtm_seq = 0;
: int len;

: int main(int argc, char *argv[])
: {
: int rtsk;
: struct sockaddr_in *rtdst;
: struct sockaddr_in *rtgat;
: struct sockaddr_in *rtnet;
: register unsigned char *cp = m_rtmsg.m_space;
: int result;

: memset(&m_rtmsg,0x00, sizeof(m_rtmsg)); // zero message area
: rtm.rtm_version = RTM_VERSION;
: rtm.rtm_type = RTM_CHANGE; // RTM_ADD also fails write
: rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
: rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
: rtm.rtm_pid = getpid();
: rtm.rtm_seq = ++rtm_seq;

: /* set up sockaddrs in order of addr flags from lsb up, that means DST,
: followed by GATEWAY followed by NETMASK
: */
: rtdst = (struct sockaddr_in *)cp; // rtdst points to start of m_space
: rtdst->sin_len = sizeof(*rtdst); // it’s address is 0.0.0.0 since
: rtdst->sin_family = AF_INET; // m_space has been zeroed
: cp += sizeof(*rtdst); // point cp to after dst
: sockaddr
: rtgat = (struct sockaddr_in *)cp; // rtgat is next in m_space
: rtgat->sin_len = sizeof(*rtgat);
: rtgat->sin_family = AF_INET; // address is from command line
: if (inet_aton(argv[1],&(rtgat->sin_addr))==0) { // 0 if error occurs
: printf(“failure\n”);
: return -1;
: }
: cp += sizeof(*rtgat); // advance cp to after gateway
: rtnet = (struct sockaddr_in *)cp; // rtnet is next in m_space
: rtnet->sin_len = sizeof(*rtnet); // address is 0.0.0.0 as m_space
: rtnet->sin_family = AF_INET; // has been cleared
: cp += sizeof(*rtnet); // advance cp to after netmask

: rtm.rtm_msglen = len = cp - (unsigned char*)&m_rtmsg;

: if ((rtsk = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
: printf(“no route socket\n”);
: return -1;
: }

: // result always returns -1 here.
: if ((result = write(rtsk, (char *)&m_rtmsg, len)) < len) {
: printf(“no write to route socket, result: %d\n”,result);
: return -1;
: }
: }