2016-05-26 2 views
0

J'ai écrit un programme d'espace utilisateur qui doit installer une nouvelle route dans la table de routage. Ce que je remarque est, non si les octets sendmsg fn retours est correct, mais le programme ne parvient pas à installer une nouvelle route. Lorsque j'essaie de diagnostiquer un problème en utilisant gdb sur le noyau Linux, je trouve que des données parasites sont envoyées depuis l'espace utilisateur vers le socket netlink du noyau.Installation d'une nouvelle route dans la table de routage Linux à l'aide de la socket rtnetlink

sortie

[[email protected] rtnetlink]# ./netlink_add_route.exe 
bytes send = 52 

Code partage:

typedef struct _request 
{ 
    struct nlmsghdr netlink_header; 
    struct rtmsg rt_message; 
    char buffer[1024]; 
} req_t; 


int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) 
{ 
    /* alen is the length of the data. Add sizeof(struct rtattr) to it to accomodate 
    type, length, value format for rtattr */ 
    int len = RTA_LENGTH(alen); // (RTA_ALIGN(sizeof(struct rtattr)) + (len)) 
    struct rtattr *rta; 
    /* size of request should not be violated*/ 
    if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) 
      return -1; 

    /* go to end of buffer in request data structure*/ 
    rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); 
    /* specify attribute using TLV format*/ 
    rta->rta_type = type; 
    rta->rta_len = len; 
    memcpy(RTA_DATA(rta), data, alen); 
    /* increase the nlmsg_len to accomodate the added new attribute*/ 
    n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; 
    return 0; 
} 


static void 
initialisation(){ 
    /* initialise the request structure*/ 
    int index = 3, 
    gw = 3232236545/*192.168.4.1*/, 
    dst = 3232235776/*192.168.1.0*/; 

    memset(&request, 0, sizeof(request)); 
    /* set the nlmsg_len = nl header + underlying structure*/ 
    request.netlink_header.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); /*NLMSG_HDRLEN + sizeof(struct rtmsg);*/ 
    /* set the flags that facilitates adding a route in routing table*/ 
    request.netlink_header.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE; 
    /* note that inet_rtm_newroute() is the fn in kernel which will be eventually called to add a new route in routing table*/ 
    request.netlink_header.nlmsg_type = RTM_NEWROUTE; 
    /* Now filling the rtmsg*/ 
    request.rt_message.rtm_family = AF_INET; 
    request.rt_message.rtm_table = RT_TABLE_MAIN; 
    request.rt_message.rtm_protocol = RTPROT_BOOT;/*Route installed during boot*/ 
    request.rt_message.rtm_scope = RT_SCOPE_UNIVERSE; 
    request.rt_message.rtm_type = RTN_UNICAST; /*Gateway or direct route */ 

    /* Add routing info*/ 
    addattr_l(&request.netlink_header, sizeof(request), RTA_GATEWAY, &gw, sizeof(gw)); 
    addattr_l(&request.netlink_header, sizeof(request), RTA_DST,  &dst, sizeof(dst)); 
    addattr_l(&request.netlink_header, sizeof(request), RTA_OIF,  &index, sizeof(index)); 
    /* For adding a route, the gateway, destination address and the interface 
    will suffice, now the netlink packet is all set to go to the kernel*/ 
} 

static void 
send_request(int fd){ 
    int rc = 0; 
    struct msghdr msg; 
    struct sockaddr_nl nladdr; 
    struct iovec iov; 
    iov.iov_base = (void*)&request.netlink_header; 
    iov.iov_len = request.netlink_header.nlmsg_len ;/* Total length : from request start to end of last attribute*/ 
    memset(&nladdr, 0, sizeof(nladdr)); 
    nladdr.nl_family = AF_NETLINK; 
    nladdr.nl_pid = 0; /* For Linux Kernel */ 
    nladdr.nl_groups = 0; 

    msg.msg_name = (void *)&nladdr; 
    msg.msg_namelen = sizeof(nladdr); 
    msg.msg_iov = &iov; 
    msg.msg_iovlen = 1; 
    rc = sendmsg(fd, &msg, 0); 
    printf("bytes send = %d\n", rc); 
} 



int 
main(int argc, char *argv[]) 
{ 
struct sockaddr_nl la; 
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 
if(fd < 0){ 
    printf("socket creation failed\n"); 
    return -1; 
} 
bzero(&la, sizeof(la)); 
la.nl_family = AF_NETLINK; 
la.nl_pid = getpid(); 
la.nl_groups = 0; 
if(bind(fd, (struct sockaddr*) &la, sizeof(la)) < 0){ 
      printf("Bind failed\n"); 
      return -1; 
} 
initialisation(); 
send_request(fd); 
close(fd); 
} 

sortie gdb

Breakpoint 1, inet_rtm_newroute (skb=0xbb53f20, nlh=0xb96ed00) at net/ipv4/fib_frontend.c:732 
732  { 
(gdb) bt 
#0 inet_rtm_newroute (skb=0xbb53f20, nlh=0xb96ed00) at net/ipv4/fib_frontend.c:732 
#1 0x081f1b28 in rtnetlink_rcv_msg (skb=0xbb53f20, nlh=0xb96ed00) at net/core/rtnetlink.c:3412 
#2 0x081fcd07 in netlink_rcv_skb (skb=0xbb53f20, cb=0x81f19de <rtnetlink_rcv_msg>) 
    at net/netlink/af_netlink.c:3017 
#3 0x081efcb9 in rtnetlink_rcv (skb=0xbb53f20) at net/core/rtnetlink.c:3418 
#4 0x081fc7e4 in netlink_unicast_kernel (ssk=<optimized out>, skb=<optimized out>, sk=<optimized out>)  at net/netlink/af_netlink.c:1834 
#5 netlink_unicast (ssk=0xbb03000, skb=0xbb53f20, portid=0, nonblock=0) at net/netlink/af_netlink.c:1860 
#6 0x081fcbf3 in netlink_sendmsg (sock=0xa50a700, msg=0xbb71e3c, len=52) at net/netlink/af_netlink.c:2511 
#7 0x081cf181 in sock_sendmsg_nosec (msg=<optimized out>, sock=<optimized out>) at net/socket.c:611 
#8 sock_sendmsg (sock=0xa50a700, msg=<optimized out>) at net/socket.c:621 
#9 0x081cf781 in ___sys_sendmsg (sock=0xa50a700, msg=<optimized out>, msg_sys=0xbb71e3c, flags=0, 
    used_address=0x0) at net/socket.c:1947 
#10 0x081d044f in __sys_sendmsg (fd=3, msg=0xbfd5cc40, flags=0) at net/socket.c:1981 
#11 0x081d0a97 in SYSC_sendmsg (flags=<optimized out>, msg=<optimized out>, fd=<optimized out>) 
    at net/socket.c:1992 
#12 SyS_sendmsg (flags=0, msg=-1076507584, fd=3) at net/socket.c:1988 
#13 SYSC_socketcall (args=<optimized out>, call=<optimized out>) at net/socket.c:2397 
#14 SyS_socketcall (call=16, args=-1076507632) at net/socket.c:2315 
#15 0x0805ba59 in handle_syscall (r=0xbbab3f0) at arch/um/kernel/skas/syscall.c:37 
#16 0x08069147 in handle_trap (local_using_sysemu=<optimized out>, regs=<optimized out>, 
    pid=<optimized out>) at arch/um/os-Linux/skas/process.c:172 
#17 userspace (regs=0xbbab3f0) at arch/um/os-Linux/skas/process.c:384 
#18 0x080594df in fork_handler() at arch/um/kernel/process.c:154 
#19 0x00000000 in ??() 
(gdb) f 6 
#6 0x081fcbf3 in netlink_sendmsg (sock=0xa50a700, msg=0xbb71e3c, len=52) at net/netlink/af_netlink.c:2511 
2511   err = netlink_unicast(sk, skb, dst_portid, msg->msg_flags&MSG_DONTWAIT); 
(gdb) p msg 
$1 = (struct msghdr *) 0xbb71e3c 
(gdb) p *(struct msghdr *) 0xbb71e3c 
$2 = {msg_name = 0xbb71d98, msg_namelen = 12, msg_iter = {type = 1, iov_offset = 0, count = 0, { 
     iov = 0xbb71d60, kvec = 0xbb71d60, bvec = 0xbb71d60}, nr_segs = 0}, msg_control = 0x4, 
    msg_controllen = 0, msg_flags = 0, msg_iocb = 0x0} 
(gdb) f 10 
#10 0x081d044f in __sys_sendmsg (fd=3, msg=0xbfd5cc40, flags=0) at net/socket.c:1981 
1981   err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL); 
(gdb) p msg 
$3 = (struct user_msghdr *) 0xbfd5cc40 
(gdb) p *(struct user_msghdr *) 0xbfd5cc40 
Cannot access memory at address 0xbfd5cc40 

Comme vous pouvez le voir ci-dessus, le msg recieved dans le noyau n'est pas accessible. Quand j'applique le gdb sur sendmsg fn dans l'application et développe le msg étant envoyé au noyau, je trouve tout parfait. Qu'est-ce qui provoque cette corruption de msg entre l'espace utilisateur et le noyau? Quelqu'un peut-il aider à diagnostiquer le problème? J'utilise le noyau version 4.5.3.

partage le lien vers le fichier src si quelqu'un veut exécuter le programme. https://drive.google.com/file/d/0B56H_R1fVFZXRjNWRkZ3M09pY2s/view?usp=sharing

Merci.

Répondre

0

Je pourrais réussir à le faire fonctionner. Le problème est la façon dont RTA_DST et RTA_GATEWAY sont ajoutés. Vous devez utiliser inet_prefix pour dst. Veuillez noter que dst.data [], dst.bytelen et dst.bitlen ne sont que des valeurs aléatoires. Veuillez initialiser au besoin pour votre solution. (Ce qui est juste pour démontrer que ça marche!)

typedef struct 
{ 
     __u16 flags; 
     __u16 bytelen; 
     __s16 bitlen; 

     __u16 family; 
     __u32 data[8]; 
} inet_prefix; 


    inet_prefix dst; 
    dst.data[0] = 11; 
    dst.data[1] = 12; 
    dst.data[2] = 13; 
    dst.data[3] = 14; 
    dst.data[4] = 15; 
    dst.data[5] = 16; 
    dst.data[6] = 17; 
    dst.data[7] = 17; 
    dst.bytelen = 32; 
    dst.bitlen = dst.bytelen * 8; 

/* mask */ 
request.rt_message.rtm_dst_len = 24; 

//addattr_l(&request.netlink_header, sizeof(request), RTA_GATEWAY, &gw, sizeof(gw)); 
addattr_l(&request.netlink_header, sizeof(request), RTA_DST,  &dst, sizeof(dst)); 

Comme un échantillon j'ai ajouté l'entrée « dst » et commenté l'entrée « gw ». Pour 'gw' aussi, vous devez suivre une structure similaire inet_prefix.

Entrée créé:

12.0.32.0  0.0.0.0   255.255.255.0 U  0  0  0 eth0 
+0

n'a pas vu de ces détails pour la configuration de la table de routage du noyau. Quelle version du noyau vous l'avez fait fonctionner? Je vais tester votre soln sur le noyau 4.5 et mettre à jour. Merci beaucoup. –

+0

Je l'ai testé le 3.19.0-49. – Pramod

+0

@abhishek, "N'a pas vu de tels détails pour la configuration de la table de routage du noyau" qu'est-ce que cela signifie? – Pramod