[英]Wrong port on startup (recvfrom)
在編寫小型DNS服務器並將其最小化時,我偶然發現了一個奇怪的行為。 該程序應在127.0.0.1:1337上偵聽DNS查詢,然后拒絕。 我通過發出dig @localhost -p 1337 foo.bar.
測試其行為dig @localhost -p 1337 foo.bar.
如果第48行被注釋掉//char bout[bufferSize]; // <-- WTF
//char bout[bufferSize]; // <-- WTF
就像魅力一樣。
程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
static int SOCKET;
void bindSocket(){
int s = socket (AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
fprintf (stderr, "Could not create socket\n");
exit (EXIT_FAILURE);
}
struct sockaddr_in address;
memset((char *)&address, 0, sizeof(address));
inet_aton("127.0.0.1", &address.sin_addr);
address.sin_family = AF_INET;
address.sin_port = htons(1337);
int rc = bind ( s, (struct sockaddr *) &address, sizeof (address) );
if (rc < 0) {
fprintf (stderr, "Could not bind Socket\n %s \n", strerror(errno));
exit (EXIT_FAILURE);
}
SOCKET = s;
}
void decline(uint16_t err, char *bin, struct sockaddr *to){
char bout[12];
memset((bout + 4), 0, 8);
memcpy(bout, bin, 4);
bout[2] = (bout[2] | 0x80) & 0xFE;
bout[3] = (bout[3] | err ) & 0x7F;
sendto( SOCKET, bout, 12, 0, to, sizeof(struct sockaddr) );
}
void hereBeDragons(){
size_t bufferSize = 512;
char bin[bufferSize];
char bout[bufferSize]; // <-- WTF
struct sockaddr sender;
socklen_t len;
while(1){
memset(bin, 0, bufferSize);
int n = recvfrom( SOCKET, bin, bufferSize, 0, &sender, &len );
if (n < 0) continue;
puts("receved a query");
/* Strictly decline all invalid queries */
decline( 2, bin, &sender);
}
}
int main(){
bindSocket();
hereBeDragons();
return EXIT_FAILURE;
}
程序輸出:
received a query
挖掘輸出:
; <<>> DiG 9.9.5-3-Ubuntu <<>> @localhost -p 1337 foo.bar.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 37520
;; flags: qr ad; QUERY: 0, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
;; Query time: 1 msec
;; SERVER: 127.0.0.1#1337(127.0.0.1)
;; WHEN: Fri Aug 29 21:37:46 CEST 2014
;; MSG SIZE rcvd: 12
這只是一個簡化的示例,在實際代碼中bout用於構造對傳入查詢的有效響應。 但是,當我將其保留時,會出現以下問題:
5秒鍾后,程序將答案發送到錯誤的端口,然后將其發送到正確的端口。
我究竟做錯了什么?
這是一個非常微妙的錯誤。
套接字地址長度參數,即recvfrom()的第六個參數,必須初始化。 必須設置它以指示在第五個參數中傳遞的地址緩沖區的長度。 當recvfrom()返回時,長度會更新以反映寫入它的網絡地址結構的實際大小。
在調用recvfrom()之前,添加:
len=sizeof(sender);
在recvfrom(2)手冊頁中對此進行了解釋:
參數addrlen是一個值結果參數,調用方應在調用與src_addr相關聯的緩沖區大小之前對其進行初始化,並在返回時進行修改以指示源地址的實際大小
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.