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.
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. –
Je l'ai testé le 3.19.0-49. – Pramod
@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