# 網路程式設計 AF_NETLINK
###### tags: `linux` `AF_NETLINK` `network programming`
<style>
.blue {
color: blue;
}
.bgblue {
color: blue;
font-size: 24px;
font-weight: bold;
}
.red {
color: red;
font-size: 24px;
font-weight: bold;
}
h1 {text-align: center;}
</style>
Author: WhoAmI
Date: 20230522
E-mail: kccddb@gmail.com
Copyright: CC BY-NC-SA
---

user space 與 kernel Space 透過 Netlink Socket, [getsockopt, setsockopt - get and set options on sockets](https://linux.die.net/man/2/setsockopt) 溝通, e.g., iproute2, tc, iptables, udev 等
(Linux 最好用 ip route 而不要用 route!
用 ip addr ...)
偵測 斷線 也不要用 ping, 例如 PPP, PPPoE 最好透過 netlink socket.
[Kernel Korner - Why and How to Use Netlink Socket, by Kevin Kaichuan He on January 5, 2005](https://www.linuxjournal.com/article/7356)
[How to use netlink socket to communicate with a kernel module?](https://stackoverflow.com/questions/3299386/how-to-use-netlink-socket-to-communicate-with-a-kernel-module/3334782)
[Monitoring Linux networking state using netlink
Oleg Kutkov / February 14, 2018](https://olegkutkov.me/2018/02/14/monitoring-linux-networking-state-using-netlink/)


[Netfilter Architecture](https://www.netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-3.html)

iptables 是 user space 軟體用來設定網路核心的工具程式
Netflter 才是真正 Linux 網路核心部分
**了解 Netflter Architecture 更能了解 Linux 網路核心的運作! 了解網路核心運作後, iptables 的使用就可靠自己練習 iptables 的用法**
https://www.netfilter.org/
netfilter.org is home to the software of the packet filtering framework inside the Linux 2.4.x and later kernel series. Software commonly associated with netfilter.org is iptables.
HOWTO
https://www.netfilter.org/documentation/index.html#documentation-howto
e.g., Linux 2.4 Packet Filtering HOWTO
Ubuntu
Iptables is a firewall, installed by default on all official Ubuntu distributions (Ubuntu, Kubuntu, Xubuntu).
https://help.ubuntu.com/community/IptablesHowTo
Source NAT/Masquerading/Destination NAT
[Linux 2.4 NAT HOWTO](https://www.netfilter.org/documentation/HOWTO//NAT-HOWTO.html#toc1)
iptables 基本使用
[THE BEGINNER’S GUIDE TO IPTABLES, THE LINUX FIREWALL BY KORBIN BROWN FEBRUARY 6, 2014, 12:34PM EDT](https://www.howtogeek.com/177621/the-beginners-guide-to-iptables-the-linux-firewall/)

```c=
/*
* route detect
*
*/
#include <asm/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <err.h>
#include <stdio.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#if 0
//#define MYPROTO NETLINK_ARPD
#define MYMGRP RTMGRP_NEIGH
// if you want the above you'll find that the kernel must be compiled with CONFIG_ARPD, and
// that you need MYPROTO=NETLINK_ROUTE, since the kernel arp code {re,ab}uses rtnl (NETLINK_ROUTE)
#else
#define MYPROTO NETLINK_ROUTE
#define MYMGRP (RTMGRP_IPV4_ROUTE|RTMGRP_IPV4_IFADDR)
#endif
#define WARN_IF(EXP) \
do { if (EXP) \
fprintf (stderr, "Warning: " #EXP "\n"); } \
while (0)
struct msgnames_t {
int id;
char *msg;
} typenames[] = {
#define MSG(x) { x, #x }
MSG(RTM_NEWLINK),
MSG(RTM_DELLINK),
MSG(RTM_NEWADDR),
MSG(RTM_DELADDR),
MSG(RTM_NEWROUTE),
MSG(RTM_DELROUTE),
MSG(RTM_GETROUTE),
#undef MSG
{0,0}
};
char *lookup_name(struct msgnames_t *db,int id)
{
static char name[512];
struct msgnames_t *msgnamesiter;
for(msgnamesiter=db;msgnamesiter->msg;++msgnamesiter) {
if (msgnamesiter->id == id)
break;
}
if (msgnamesiter->msg) {
return msgnamesiter->msg;
}
snprintf(name,sizeof(name),"#%i",id);
return name;
}
int open_netlink()
{
int sock = socket(AF_NETLINK,SOCK_RAW,MYPROTO);
//int sock = socket(AF_ROUTE,SOCK_RAW,MYPROTO);
struct sockaddr_nl addr;
memset((void *)&addr, 0, sizeof(addr));
if (sock<0)
return sock;
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = MYMGRP;
if (bind(sock,(struct sockaddr *)&addr,sizeof(addr))<0)
return -1;
return sock;
}
int read_event(int sock)
{
struct sockaddr_nl nladdr;
struct msghdr msg;
struct iovec iov[2];
struct nlmsghdr nlh;
char buffer[65536];
int ret;
int i=0;
iov[0].iov_base = (void *)&nlh;
iov[0].iov_len = sizeof(nlh);
iov[1].iov_base = (void *)buffer;
iov[1].iov_len = sizeof(buffer);
msg.msg_name = (void *)&(nladdr);
msg.msg_namelen = sizeof(nladdr);
msg.msg_iov = iov;
msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]);
ret=recvmsg(sock, &msg, 0);
i++;
if (ret<0) {
return ret;
}
///printf("%s\n",CMSG_DATA((struct cmsghdr *)msg.msg_control));
if(nlh.nlmsg_type==RTM_DELADDR){
printf("%d[DEL ADDR %d]\n",i,nlh.nlmsg_type);
}
printf("Type: %i (%s)\n",(nlh.nlmsg_type),lookup_name(typenames,nlh.nlmsg_type));
printf("Flag:");
#if 0
#define FLAG(x) if (nlh.nlmsg_type & x) printf(" %s",#x)
FLAG(NLM_F_REQUEST);
FLAG(NLM_F_MULTI);
FLAG(NLM_F_ACK);
FLAG(NLM_F_ECHO);
FLAG(NLM_F_REPLACE);
FLAG(NLM_F_EXCL);
FLAG(NLM_F_CREATE);
FLAG(NLM_F_APPEND);
#undef FLAG
#endif
printf("\n");
printf("Seq : %i\n",nlh.nlmsg_seq);
printf("Pid : %i\n",nlh.nlmsg_pid);
printf("\n");
return 0;
}
int main(int argc, char *argv[])
{ int nls = open_netlink();
if (nls<0) {
err(1,"netlink");
}
while (1)
read_event(nls);
return 0;
}
```
