Raw Sockets
원문 : UNIX NETWORK PROGRAMMING Volume 1 SECOND EDITION, W.RICHARD STEVENS
Introduction
Raw Sockets은 TCP와 UDP socket들이 제공하지 않는 세 가지 특징을 제공한다.
- Raw sockets은 ICMPv4, ICMPv6, IGMPv4 packet을 읽고 쓸 수 있게 한다. 예를 들어 Ping program은 ICMP echo 요청을 보내고 ICMP echo 응답을 받는다. Muticast routing daemon인 mrouted는 IGMPv4 packet을 보내고 받는다.
또한 이 기능들은 ICMP나 IGMP를 사용하여 만들어진 응용들이 kernel에 더 많은 code를 넣는 대신 사용자 process로 처리 되도록 허락한다.
예를 들어 router discovery daemon은 이런 방식으로 만들어진다. 이 daemon은 kernel이 알지 못하는 두개의 ICMP messages (router advertisement, router solicitation message)을 처리한다.
- Raw sockets에서 process는 kernel에 의해 처리되지 않은 IPv4 protocol field를 가진 IPv4 datagrams을 읽고 쓸 수 있다. 대부분의 kernel들은 단지 1(ICMP), 2(IGMP), 6(TCP), 17(UDP)의 값을 가진 datagrams을 처리한다. 하지만 protocol field를 위해서 많은 다른 값들이 정의되어 있다.
예를 들어 OSPF routing protocol은 IP datagram의 protocol field를 89로 설정함으로써 TCP나 UDP를 사용하지 않고 IP를 직접 사용한다.
OSPF를 실행하는 gated program은, kernel이 전혀 알지 못하는 protocol field를 가지기 때문에, 이 IP datagrams을 읽고 쓰기 위해서 raw socket을 이용해야만 한다.IPv6에도 이 기능이 지원된다.
- IP_HDRINCL socket option을 사용하여, raw socket에서 process는 자신의 IPv4 header를 만들 수 있다. 예를 들어, UDP나 TCP packet을 만드는데 사용될 수 있다.
Raw Socket Creation
Raw Socket을 생성하는 과정은 다음과 같다.
- 두번째 argument가 SOCK_RAW일때 socket function은 raw socket을 생성한다. 세번째 argument(protocol)는 일반적으로 0이 아닌 값을 가진다. 예를 들어, IPv4 raw socket을 생성하기 위해서 다음과 같이 쓸수 있다.
int sockfd;
sockfd = socket(AF_INET, SOCK_RAW, protocol);
여기서 protocol은를 포함함으로 정의된 IPPROTO_ICMP 같은 IPPROTP_xxx 형식의 상수 중의 하나이어야 한다.
IPPROTP_EGP라는 식으로 이 header에만 그 이름들이 정의되어있기 때문에 kernel이 그 이름들을 지원하는 것은 아니라는 것을 기억해야 한다. 오직 관리자만이 raw socket을 생성할 수 있다. 이것은 일반 사용자들이 network에 자신들의 IP datagram을 쓰는 것을 방지한다.
- IP_HDRINCL socket option은 다음과 같이 설정될 수 있다.
const int on = 1;
if( setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0)
error
- bind는 raw socket에서 호출될 수 있지만 이런 일은 드물게 일어난다. 이 함수는 단지 local address를 설정한다. raw socket에는 port number의 개념이 없다.
출력에 관해서는 bind를 호출하여 raw socket으로 보내질 datagram에 사용될 source IP address를 설정한다. (IP_HERINCL socket option이 설정되지 않을 때에만) 만약 bind가 호출되지 않으면 kernel은 출력 interface의 첫번 IP address로 source IP address를 설정한다.
- connect는 raw socket에서 호출될 수 있지만 이런 일은 드물게 일어난다. 이 함수는 단지 외부 address를 설정한다.
위에서 말했지만 raw socket은 port number의 개념이 없다. 출력에 관해서는, 이미 destination IP address가 설저오디어 있기 때문에 connect의 호출이 sendto function 대신에 write나 send function를 호출할 수 있게 한다.
Raw Socket Output
Raw Socket의 출력은 다음과 같은 규칙으로 이루어진다.
- 정상적인 출력은 sendto나 sendmsg 중 하나를 호출하고 destination IP address를 지정하여 이루어진다. write, writev 또는 send는 만약 socket이 이미 연결되어 있으면 호출될 수 있다.
- 만약 IP_HDRINCL option이 설정되 있지 않으면, kernel이 IP header를 만들고 process로부터 data에 그 address를 덧붙이기 때문에, 쓰려고 하는 kernel을 위한 data의 starting address는 IP header 뒤의 처음 byte를 명시한다.
Kernel은 socket function에 대한 호출로부터 세번째 argument를 만드는 IPv4 header의 protocol field를 설정한다.
- 만약 IP_HDRINCL option이 설정되면, 쓰려고 하는 kernel을 위한 starting address는 IP header의 처음 byte를 명시한다. 쓰려고 하는 data의 양은 호출한 쪽의 IP header의 크기를 포함해야 한다.
process는 (a) IPv4 확인 field는 0으로 설정될 수 있고, 이것은 kernel이 이 값을 설정할 때와 (b) kernel은 항상 IPv4 header 오류 검사용 checksum을 계산하고 저장할 때를 제외하고 전체적인 IP header를 만든다.
- kernel은 출력 interface MTU를 초과하는 순수 packets을 작은 조각으로 만든다.
Raw Socket Input
Raw Socket에 관해서 대답해야 하는 첫번째 질문은 수신된 IP datagram이 kernel이 raw socket에 넘긴 것인가 하는 것이다. 다음과 같은 규칙이 적용된다.
- 수신된 UDP packets과 TCP packets은 절대로 raw socket으로 전달되지 않는다. 만약 process가 UDP나 TCP packet을 포함한 IP datagram을 읽기 원하면, packet은 data link layer에서 읽혀져야 한다.
- kernel이 ICMP message 처리를 끝낸 후에 대부분의 ICMP packets은 raw socket으로 전달된다. Berkeley 파생 구현들은 모든 수신된 ICMP packets을 echo 요청이나 timestamp 요청 address mask(선별) 요청과는 다른 raw socket으로 넘긴다. 이 세 개의 ICMP messages은 전적으로 kernel에 의해서 처리된다.
- kernel이 IGMP message 처리를 끝낸 후에 모든 IGMP packets은 raw socket으로 전달된다.
- kernel이 이햐하지 못하는 protocol field를 가진 모든 IP datagram은 raw socket으로 전달된다. 이 packets에서 kernel이 처리하는 것은 몇 가지 IP header field에 대한 최소한의 검사뿐이다.( IP Version, IPv4 header checksum, header length and the destination IP address 등 )
- 만약 datagram이 조각나서 도착되면, 모든 조각들이 도착해서 재조합될 때까지 아무 것도 raw socket으로 넘겨지지 않는다.
kernel이 raw socket에 넘길 IP datagram을 가지고 있을 때, 전체 process를 위한 모든 raw sockets은 검사되고, 적합하게 맞아 떨어지는 모든 sockets을 찾는다. 맞아 떨어지는 각 socket으로 IP datagram의 복사본이 전달된다.
각 raw sockets을 위한 다음의 검사가 수행되고 다음의 세 가지 검사가 모두 옳을 때만 datagram은 socket으로 전달된다.
- raw socket이 생성되었을 때( socket에 대한 세번째 argument ) 만약 0이 아닌 protocol이 명시되어 있으면, 수신된 datagram의 protocol field는이 값과 맞아 떨어져야만 한다. 그렇지 않으면 datagram은 이 socket으로 전달되지 않는다.
- 만약 local address가 bind function에 의해서 raw socket에 설저오디어 있으면, 수신된 datagram의 destination IP address는 이 address와 맞아 떨어져야만 한다. 그렇지 않으면 datagram은 socket으로 전달되지 않는다.
- 만약 foreign IP address가 connect function에 의해서 raw socket을 위해 명시되어 있으면, 수신된 datagram의 source IP address는 이 연결된 address와 맞아 떨어져야만 한다. 그렇지 않으면 datagram은 이 socket으로 전달되지 않는다.
만약 protocol 값을 0으로 해서 raw socket이 생성되고 bind나 connect 둘 중의 아무 것도 호출되지 않으면, socket은 kernel이 raw socket으로넘긴 각 raw datagram의 복사본을 수신한다. 수신된 datagram이 raw IPv4 socket으로 넘겨질 때마다, IP header를 포함한 전체 datagram은 process로 넘겨진다.
IPv6 header와 어떤 확장 header들도 결코 순수 IPv6 socket으로 넘겨지지 않는다. 응용에 전달된 IPv4 header에서, ip_len, ip_off 그리고 ip_id는 host byte order이고 나머지 fields은 network byte order이다. linux에서는 모든 fields는 network byte order로 남겨져 있다. raw IPv6 socket으로 전달된 datagram의 모든 fields은 network byte order로 남겨져 있다.
SOCK_RAW 설명.
'프로그래밍 > VC++ 개발 코딩' 카테고리의 다른 글
CppCheck (정적분석도그) 프로그램 VS 6.0 연동 방법 (0) | 2014.01.23 |
---|---|
BSD Socket 사용방법 (0) | 2014.01.17 |
fopen 사용방법 (0) | 2014.01.17 |
VS6.0 STL 사용 주의사항 (0) | 2014.01.17 |
Registry Write (0) | 2014.01.17 |