[Linux] rtnetlink(3)
2021. 5. 31. 19:13기본 지식
rtnetlink - Linux routing socket 의 의미이다.
- 사용법
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
rtnetlink_socket = socket(AF_NETLINK, int socket_type, NETLINK_ROUTE);
1) RTA는 "Routing attributes" 의 줄임말이다.
- Routing attributes
Some rtnetlink messages have optional attributes after the initial header:
struct rtattr {
unsigned short rta_len; /* Length of option */
unsigned short rta_type; /* Type of option */
/* Data follows */
};
2) RTM은 "Message"
- Messages
Rtnetlink consists of these message types (in addition to standard netlink messages):
RTM_NEWLINK, RTM_DELLINK, RTM_GETLIN
3) ifa_family는 interface address family를 일컫는 용어.
IFA는 interface address의 줄임말
All rtnetlink(7) messages consist of a netlink(7) message header and appended attributes.
그 속성들은 오직 여기에 제공된 매크로를 사용하면서 조작되어야만 합니다.
RTA_OK (rta, attrlen)는 rta가 유효한 라우팅 속성을 가리키면 true를 반환합니다. attrlen은 속성 버퍼의 실행 길이입니다. true가 아니라면 여러분은 이 메시지 안에 어떠한 속성도 있지 않음을 가정해야합니다. attrlen이 0이 아니어도 말이죠.
RTA_DATA(rta) 이 속성의 데이터의 시작 포인터를 반환합니다.
RTA_PAYLOAD(rta) 이 속성 데이터의 길이를 반환합ㄴ디ㅏ.
RAT_NEXT(rta, attrlen)는 rta 이후의 다음 속성(attribute)를 얻습니다. 이 매크로를 호출하는 것은 attrlen이 업데이트 될 것입니다. 여러분은 반환되는 포인터의 유효성을 검증하기 위해 RTA_OK를 사용해야만 합니다.
RTA_LENGTH (len)은 len bytes의 데이터와 헤더에 필요한 길이를 반환합니다.
RTA_SPACE (len)는 len 바이트의 데이터가있는 메시지에 필요한 공간을 반환합니다.
CONFORMING TO
이 매크로들은 비표준 Linux 확장입니다.
예제 (주석 없음)
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
int main()
{
struct sockaddr_nl addr;
int sock, len;
char buffer[4096];
struct nlmsghdr *nlh;
if ((sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {
perror("couldn't open NETLINK_ROUTE socket");
return 1;
}
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_groups = RTMGRP_IPV4_IFADDR;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("couldn't bind");
return 1;
}
nlh = (struct nlmsghdr *)buffer;
while ((len = recv(sock, nlh, 4096, 0)) > 0) {
while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) {
if (nlh->nlmsg_type == RTM_NEWADDR) {
struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
struct rtattr *rth = IFA_RTA(ifa);
int rtl = IFA_PAYLOAD(nlh);
while (rtl && RTA_OK(rth, rtl)) {
if (rth->rta_type == IFA_LOCAL) {
char name[IFNAMSIZ];
if_indextoname(ifa->ifa_index, name);
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, RTA_DATA(rth), ip, sizeof(ip));
printf("interface %s ip: %s\n", name, ip);
}
rth = RTA_NEXT(rth, rtl);
}
}
nlh = NLMSG_NEXT(nlh, len);
}
}
return 0;
}
예제 (주석 있음)
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
int main()
{
struct sockaddr_nl addr;
int sock, len;
char buffer[4096];
struct nlmsghdr *nlh;
if ((sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {
perror("couldn't open NETLINK_ROUTE socket");
return 1;
}
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
// Routing Message Group of IPv4 Inteface address로 그룹을 지정
addr.nl_groups = RTMGRP_IPV4_IFADDR;
// 해당 netlink 그룹으로 sock 바인딩.
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("couldn't bind");
return 1;
}
nlh = (struct nlmsghdr *)buffer;
// nlh라는 변수에 담을 예정.
while ((len = recv(sock, nlh, 4096, 0)) > 0) {
// OK 이고, NLMSG_DONE 타입이 아니라면 진행.
while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) {
if (nlh->nlmsg_type == RTM_NEWADDR) {
struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
struct rtattr *rth = IFA_RTA(ifa);
int rtl = IFA_PAYLOAD(nlh);
while (rtl && RTA_OK(rth, rtl)) {
if (rth->rta_type == IFA_LOCAL) {
char name[IFNAMSIZ];
if_indextoname(ifa->ifa_index, name);
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, RTA_DATA(rth), ip, sizeof(ip));
printf("interface %s ip: %s\n", name, ip);
}
rth = RTA_NEXT(rth, rtl);
}
}
// 그다음 넷링크 메시지로.
nlh = NLMSG_NEXT(nlh, len);
}
}
return 0;
}
참고자료
https://stackoverflow.com/questions/579783/how-to-detect-ip-address-change-programmatically-in-linux
'Linux > Linux명령어' 카테고리의 다른 글
[Linux] find 명령어 (0) | 2021.07.04 |
---|---|
[Linux] Nohup 명령어, 세션 끊김 영향없이 명령어 실행해라. non-tty로 출력한채로. (0) | 2021.06.14 |
[Linux] repquota 명령어, 유저별 용량 제한해라 (0) | 2021.05.12 |
[Linux] lsblk 명령어, 블록 디바이스들을 나열해라 [미완성] (0) | 2021.05.08 |
[Linux] growpart 명령어, 파티션 테이블 안에 있는 파티션을 확장해라 (0) | 2021.05.05 |