Standard or Build in

基本上只要是系統本身提供的函數發生錯誤時都會設定errno,而取代原函數的新函數則不會有返回值、參數以及功能的解釋,因為與原函數功能幾乎相同。

地址轉換相關

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

char *inet_ntoa(struct in_addr in);
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);

這些函數最好別再使用,改用inet_ntop()inet_pton()代替。


char *inet_ntoa(struct in_addr in);
  • 返回值:成功IPv4地址字串,失敗傳回NULL。
  • 參數:in網路順序的地址。
  • 功能:將網路順序的地址轉成字串的IPv4地址。


int inet_aton(const char *cp, struct in_addr *inp);
  • 返回值:成功傳回非0,失敗傳回0。
  • 參數:cp為字串的IPv4地址。inp網路順序結構結果。
  • 功能:將字串的IPv4地址轉成網路順序結構。


in_addr_t inet_addr(const char *cp);
  • 返回值:成功傳回網路順序,失敗傳回-1。
  • 參數:cp為字串的IPv4地址。
  • 功能:與inet_aton()相同,但是本身有bug,像是給參數255.255.255.255會傳回-1。

這邊可能會注意到說,為什麼inet_ntoa()可以傳回一個字串,這要獨立一篇來講:如何傳回一個字串


#include <arpa/inet.h>

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
int inet_pton(int af, const char *src, void *dst);

可以支援IPv6且較安全。n表示networkp表示presentation也能記做printable,所以ntop可以記成network to presentation


const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
  • 返回值:成功傳回dst參數,失敗傳回NULL。
  • 參數:af只有AF_INETAF_INET6表示不是IPv4就是IPv6。src網路順序地址。dst結果字串。size結果字串陣列長度。
  • 功能:將網路順序的地址轉成字串,dst陣列大小如果是IPv4可以用INET_ADDRSTRLEN,IPv6則是INET6_ADDRSTRLEN這兩個巨集(Macros)。


int inet_pton(int af, const char *src, void *dst);
  • 返回值:成功傳回1,失敗傳回-1,輸入字串地址不正確傳回0。
  • 參數:af只有AF_INETAF_INET6表示不是IPv4就是IPv6。src字串地址。dst網路順序結果。
  • 功能:將字串的地址轉成網路順序,dst如果是IPv4可以用struct sockaddr_in儲存,IPv6則是struct sockaddr_in6


#include <sys/types.h>
#include <sys/socket.h>
#include <net/ethernet.h>

struct ether_addr *ether_aton(const char *a);
char *ether_ntoa(const struct ether_addr *n);

乙太的硬體地址,俗稱MAC Address,能夠過這兩個函數:函數ether_aton()和函數ether_ntoa()轉換成網路封包能夠的結構。


struct ether_addr *ether_aton(const char *a);
  • 返回值:一個網路封包能夠的地址結構指標,失敗傳回NULL。
  • 參數:a要轉換的MAC Address字串。
  • 功能:將字串轉成網路封包用的地址結構指標。


char *ether_ntoa(const struct ether_addr *n);
  • 返回值:MAC Address字串,失敗傳回NULL。
  • 參數:n要轉換的網路封包用的地址結構指標。
  • 功能:將網路封包用的地址結構指標轉成字串。

這兩個函數都有如何傳回一個字串內所提到傳回同一個地址的問題。

網路順序相關

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);
uint32_t ntohl(uint32_t netlong);
uint16_t htons(uint16_t hostshort);
uint16_t ntohs(uint16_t netshort);

這幾個函數都是轉換網路順序及主機順序的函數,這邊要稍微介紹一下兩種Byte order。

  1. Network byte order
  2. Host byte order

一般來講Network byte orderBig‐Endian,而Host byte order通常是Little‐Endian,這是電腦在儲存資料byte放的順序方式。

剛學程式的時候,一定會有一種題目這像這樣:

int x = 0x12345678;
char c = x;
c = ?

答案c=0x78,因為電腦是Host byte order,是從後面取的資料。

但是在網路上可能會跟常理有點顛倒。同樣一個資料0x12ac,在封包內為:

0x120xac

但是當我們用一個指標x指向這個封包時:

x
封包(0x12ac)

則:

printf("%#x", *x);

輸出結果為:0xac12,因為是從後面取資料,所以我們必須去轉換它。

幸運的是我們不必了解我們系統到底是屬於哪種Byte order,我們只要利用htonl()ntohl()htons()以及ntohs()即可完成,這四個函數的記法很簡單,h表示hostn表示networkl表示四個byte的資料(unsigned long),s表示兩個byte的資料(unsigned short)。

所以今天如果要從封包內讀取一個兩個byte的資料,就要使用ntohs()來轉換。

字串處理相關

#include <string.h>

size_t strlcpy(char * restrict dst, const char * restrict src, size_t size);
size_t strlcat(char * restrict dst, const char * restrict src, size_t size);

這兩個函數用來取代原本的函數strcpy()和函數strcat(),舊的函數並沒有傳入長度,所以容易造成緩衝區溢位(bufer overflow),新的函數唯一差別在多了第三個參數,第三個參數要傳入dst的大小,這樣就不會造成緩衝區溢位。雖然這兩個函數並不是標準函數,但在大多數的Linux系統已經實作出來了。在Windows上則使用函數strcpy_s()和函數strcat_s(),差別在第二三參數順序顛倒。

主機訊息相關

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);

void freeaddrinfo(struct addrinfo *ai);

函數getaddrinfo()和函數freeaddrinfo()是一對的。函數getaddrinfo()可以用來將主機名稱轉成IP地址或是可以準備連線的前置作業,而函數freeaddrinfo()是用來釋放從函數getaddrinfo()取得的鏈結串鏈結構。


int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
  • 返回值:成功傳回0,失敗傳回error code,由函數gai_strerror()取得錯誤訊息。
  • 參數:hostname主機名稱或是IP地址。servname填入Port號碼或是服務名稱(/etc/services內定義),可以為NULL。hints主機其他需求資訊。res結果鏈結串列指標。
  • 功能:主要用來取代舊函數gethostbyname(),新的函數不只可以用來查詢DNS名字也可以能拿查詢服務名稱,並且也把結構給填寫好,可用來下一步連線使用。


void freeaddrinfo(struct addrinfo *ai);
  • 參數:ai要釋放的鏈結串鏈指標。
  • 功能:用來釋放從函數getaddrinfo()取得的鏈結串列指標。


#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags);
  • 返回值:成功傳回0,失敗傳回error code,由函數gai_strerror()取得錯誤訊息。
  • 參數:saSocket地址。salenSocket地址結構長度。host主機名稱結果陣列。hostlen主機名稱結果陣列長度。serv服務結果陣列。servlen服務結果陣列長度。flagsˋ標記,可以使用NI_NOFQDNNI_NUMERICHOSTNI_NAMEREQDNI_NUMERICSERV以及NI_DGRAM
  • 功能:主要用來將IP地址轉成主機名稱或是用來取得服務的名稱,取代了舊函數gethostbyaddr()以及函數getservbyport()


#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

const char *gai_strerror(int ecode);
  • 返回值:ecode所對應的錯誤訊息。
  • 參數:ecode錯誤代碼。
  • 功能:將當函數getaddrinfo()或函數getnameinfo()發生錯誤時所回傳的代碼轉成字串。

處理參數相關

#include <unistd.h>

extern char *optarg;
extern int optind;
extern int optopt;
extern int opterr;

int getopt(int argc, char * const argv[], const char *optstring);
  • 返回值:成功讀到的選項,失敗傳回-1,結束傳回EOF。
  • 參數:argc參數數量。argv參數陣列。optstring可接受的參數方式。
  • 變數:optarg目前選項的參數。optind目前要處理的Index。optopt目前讀到的選項。opterr當讀取到錯誤的選項是否要輸出錯誤到stderr。
  • 功能:參考libnet/arpoison.c

sysctl相關

#include <sys/types.h>
#include <sys/sysctl.h>

int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int sysctlnametomib(const char *name, int *mibp, size_t *sizep);

指令sysctl能夠取得或修改系統上的參數,sysctl使用一種MIB(Management Information Base)階層式名稱,這邊列出幾個主要的這邊列出幾個主要的階級: 函數sysctl()除了可以做到與指令sysctl修改參數的功能,也能夠取得Route Table、ARP Table甚至是MAC Address。


int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
  • 返回值:成功傳回0,失敗傳回-1。
  • 參數:nameMIB的階層陣列。namelenMIB階層陣列長度。oldp取得數值的buffer。oldlenp取得數值的長度。newp設定數值的buffer。newlen設定數值的長度。
  • 功能:透過MIB取得或修改系統核心參數。

第一個參數name是MIB階層的陣列,以取得Route Table為例,MIB要設定成:

int mib[6];

mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = 0;
mib[4] = NET_RT_DUMP2;
mib[5] = 0;


sysctl(mib, 6, NULL, &needed, NULL, 0);

接著因為不知道Route Table大小,所以第三個參數可以先為NULL,由第四個參數取得大小。


buf = malloc(needed));
sysctl(mib, 6, buf, &needed, NULL, 0);
...分析
free(buf);

取得大小後動態分配空間,再來取得Route Table,接著就是一連串解析取得的資料。

函數sysctl()簡單用法就是這樣,比較麻煩的是要找到MIB階層才能夠取得核心資料,假如只知道名稱階層而不知道MIB階層的話,那麼改用函數sysctlbyname()會比較方便。


int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
  • 返回值:成功傳回0,失敗傳回-1。
  • 參數:name階層名稱。oldp取得數值的buffer。oldlenp取得數值的長度。newp設定數值的buffer。newlen設定數值的長度。
  • 功能:透過階層名稱取得或修改系統核心參數。

假如我們要打開封包轉送的功能,但是我們只知道階層名稱:net.inet.ip.forwarding而不知道MIB階層,那麼就可以用該函數。


如果我們要取得目前數值的話:

int value;
sysctlbyname("net.inet.ip.forwarding", &value, sizeof(value), NULL, NULL);


如果要設定數值的話:

int value = 1;
sysctlbyname("net.inet.ip.forwarding", NULL, NULL, &value, sizeof(value));

記得修改的話,必須要有root權限。


int sysctlnametomib(const char *name, int *mibp, size_t *sizep);
  • 返回值:成功傳回0,失敗傳回-1。
  • 參數:name要轉換的階層名稱。mibp結果MIB陣列。sizep結果MIB陣列長度。
  • 功能:將名稱階層轉成MIB階層。

results matching ""

    No results matching ""