2017-08-23 44 views
1

我想通過UDP/SNMP從服務器發送一個字符串到客戶端。但是,如果我複製一個長度爲86的字符串到pdu packet->value_value一切正常,我得到客戶端的字符串。如果我只向字符串添加更多字符,則長度現在爲87,數據包無法傳遞給客戶端。數據包大小正確提升。是否有限制可以發送多少個字符?我的包是小於1500是否有限制可以通過udp/snmp發送多少個字符?

這段代碼顯示瞭如何將字符串複製到packet->value_value

value_value = "asd asd asd asd asd asd asd asd asd asd asd asd asd asd asd asd asd asd asd asd asd as"; 
printf("String length: %d\n",strlen(value_value)); // 86 OK, 87or greater NOK 
packet->value_length = strlen(value_value); 
packet->value_value = malloc(packet->value_length); 
strcpy(packet->value_value, value_value); 

對於一些信息,這裏的終端輸出有關的包中一些更多的信息長度

輸出與字符串長度86

src/agent.c:69:parse_request(): Input length=43 
src/agent.c:116:perform_snmp_request(): OID is: 1.3.6.1.2.1.1.1.0 
String length: 86 
src/mibservice.c:90:snmpget(): packet->value_type=04 
src/mibservice.c:91:snmpget(): packet->value_length=56 
src/mibservice.c:93:snmpget(): packet->value_value=61 
... 
src/mibservice.c:93:snmpget(): packet->value_value=73 
src/mibservice.c:95:snmpget(): Before packet->length=41 
src/mibservice.c:97:snmpget(): After packet->length=127 
src/mibservice.c:99:snmpget(): Before packet->pdu_length=28 
src/mibservice.c:101:snmpget(): After packet->pdu_length=114 
src/mibservice.c:103:snmpget(): Before packet->variablebindings_length=14 
src/mibservice.c:105:snmpget(): After packet->variablebindings_length=100 
src/mibservice.c:107:snmpget(): Before packet->varbind_length=12 
src/mibservice.c:109:snmpget(): After packet->varbind_length=98 
src/agent.c:96:create_response(): Output length=129 

輸出與字符串長度87

src/agent.c:69:parse_request(): Input length=43 
src/agent.c:116:perform_snmp_request(): OID is: 1.3.6.1.2.1.1.1.0 
String length: 87 
src/mibservice.c:90:snmpget(): packet->value_type=04 
src/mibservice.c:91:snmpget(): packet->value_length=57 
src/mibservice.c:93:snmpget(): packet->value_value=61 
... 
src/mibservice.c:93:snmpget(): packet->value_value=64 
src/mibservice.c:95:snmpget(): Before packet->length=41 
src/mibservice.c:97:snmpget(): After packet->length=128 
src/mibservice.c:99:snmpget(): Before packet->pdu_length=28 
src/mibservice.c:101:snmpget(): After packet->pdu_length=115 
src/mibservice.c:103:snmpget(): Before packet->variablebindings_length=14 
src/mibservice.c:105:snmpget(): After packet->variablebindings_length=101 
src/mibservice.c:107:snmpget(): Before packet->varbind_length=12 
src/mibservice.c:109:snmpget(): After packet->varbind_length=99 
src/agent.c:96:create_response(): Output length=130 

更新 這裏是我的問題可運行的例子。數據包out_buf_0代表有效的SNMP數據包,並可通過UDP發送。數據包out_buf_1是與out_buf_0相同的數據包,其末尾的一個字符多於0x64。此外,由於增加了字符,我提高了所有長度+1。爲什麼out_buf_1不是有效的SNMP數據包/爲什麼不能通過UDP發送?注意:SNMP請求無法顯示在終端中,因爲來自客戶端的request idout_buf_0out_buf_1不同,請查看wireshark以查看請求/響應。

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <netdb.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 

#define MESSAGE_MAX_LEN 1500 /* MTU, IEEE Std 802.3TM-2015 */ 
#define PORT 161 /* RFC 1157 */ 

int out_buf_0_len = 129; /* 0x7f + 2 */ 
char out_buf_0[] = { 
0x30, /* SNMP Packet start */ 
0x7f, /* SNMP Packet length */ 
0x02, 0x01, 0x00, /* Version */ 
0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, /* Community*/ 
0xa2, /* GetResponsePDU */ 
0x72, /* GetResponsePDU Length */ 
0x02, 0x04, 0x2c, 0x80, 0x7e, 0x2f, /* Request id */ 
0x02, 0x01, 0x00, /*Error status */ 
0x02, 0x01, 0x00, /*Error index */ 
0x30, /* Varbind list start */ 
0x64, /* Varbind list length*/ 
0x30, /* Varbind value start */ 
0x62, /* Varbind value length */ 
0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, /* OID */ 
0x04, /* Value start, type octet-string*/ 
0x56, /* Value length */ 
0x61, 0x73, 0x64, 0x20, 0x61, /* Value */ 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73 }; 

int out_buf_1_len = 130; /* 0x80 + 2 */ 
char out_buf_1[] = { 
0x30, /* SNMP Packet start */ 
0x80, /* SNMP Packet length */ 
0x02, 0x01, 0x00, /* Version */ 
0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, /* Community*/ 
0xa2, /* GetResponsePDU */ 
0x73, /* GetResponsePDU Length */ 
0x02, 0x04, 0x2c, 0x80, 0x7e, 0x2f, /* Request id */ 
0x02, 0x01, 0x00, /*Error status */ 
0x02, 0x01, 0x00, /*Error index */ 
0x30, /* Varbind list start */ 
0x65, /* Varbind list length*/ 
0x30, /* Varbind value start */ 
0x63, /* Varbind value length */ 
0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, /* OID */ 
0x04, /* Value start, type octet-string*/ 
0x57, /* Value length */ 
0x61, 0x73, 0x64, 0x20, 0x61, /* Value */ 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64 }; 

int my_socket; 
struct sockaddr_in remote_addr; 
int socket_create() 
{ 
    printf("Create socket\n"); 
    struct sockaddr_in socket_addr; 
    if ((my_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
    { 
     printf("Cannot create socket. Exit.\n"); 
     return -1; 
    } 
    memset((char *)&socket_addr, 0, sizeof(socket_addr)); 
    socket_addr.sin_family = AF_INET; 
    socket_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    socket_addr.sin_port = htons(PORT); 
    if (bind(my_socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0) 
    { 
     printf("Bind failed. Exit.\n"); 
     return - 1; 
    } 
    printf("Listen on: %s:%d\n", inet_ntoa(socket_addr.sin_addr), PORT); 
    return 0; 
} 

socklen_t addr_len = sizeof(remote_addr); 
void socket_listen(char *in_buf) 
{ 
    int recv_len; /* Bytes received */ 
    int nbyt; /* Bytes count */ 
    char *out_buf[MESSAGE_MAX_LEN]; 
    int out_len = 0; 

    for (;;) { /* Receive snmp message from snmp manager */ 
     recv_len = recvfrom(my_socket, in_buf, MESSAGE_MAX_LEN, 0, (struct sockaddr *)&remote_addr, &addr_len); 
     if (recv_len > 0) 
      if (sendto(my_socket, out_buf_1, out_buf_1_len, 0, (struct sockaddr *)&remote_addr, addr_len) < 0) 
       printf("Cannot send data to destination.\n"); 
    } 
} 

/* Disable SNMP on local machine. # systemctl stop snmpd 
* Execute main(): gcc <filename>.c && ./a.out 
* Run SNMP Request: $ snmpget -v 1 -c public 0.0.0.0:161 1.3.6.1.2.1.1.1.0 
*/ 
char in_buf[MESSAGE_MAX_LEN]; 
int main(int argc, char **argv) 
{ 
    if (socket_create() == -1) 
     exit(2); 
    socket_listen(in_buf); 
} 

整個幀長度包括我的SNMPv1分組out_buf_0是1368個比特,out_buf_1應該1376比特。

+3

? 'malloc(packet-> value_length + 1);'在''strcpy'之前爲'NUL'終結符加1。或者'packet-> value_length = strlen(value_value)+ 1;'而不是。 –

+0

@WeatherVane問題是一樣的,如果我添加+1值長度是錯誤的。 – Sam

+3

您的程序會超出內存分配並導致UB。 –

回答

0

的SNMP分組長度0x80是錯的,請參閱here

的0x80的的ASN.1長度字段是錯誤的。解碼器看到第一個 您的數據包的兩個八位字節是0x30 0x80,並從該0x80 確定應該不再有八位字節。然而,還有更多的 八位字節,所以它是一個無效的編碼,並且還沒有一個有效的SNMP 消息。這裏的0x80並不意味着內容的128個八位字節,因爲你想要的是 ,這意味着你的長度字段是0x80 &〜0x80 == 0字節長 在這個字節之後。取而代之,0x81意味着您的長度字段爲 0x81 &〜0x80 == 1個八位組,後面的0x80個八位組會指示內容長度爲128。

那SNMP報文應該如何模樣,關了1

char out_buf_1[] = { 
0x30, /* SNMP Packet start */ 
0x81, 0x80, /* SNMP Packet length */ 
0x02, 0x01, 0x00, /* Version */ 
0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, /* Community*/ 
0xa2, /* GetResponsePDU */ 
0x73, /* GetResponsePDU Length */ 
0x02, 0x04, 0x2c, 0x80, 0x7e, 0x2f, /* Request id */ 
0x02, 0x01, 0x00, /*Error status */ 
0x02, 0x01, 0x00, /*Error index */ 
0x30, /* Varbind list start */ 
0x65, /* Varbind list length*/ 
0x30, /* Varbind value start */ 
0x63, /* Varbind value length */ 
0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, /* OID */ 
0x04, /* Value start, type octet-string*/ 
0x57, /* Value length */ 
0x61, 0x73, 0x64, 0x20, 0x61, /* Value */ 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61, 
0x73, 0x64 }; 
0

由於有人在評論中指出,strcpy是邪惡的,不應該用於任何事情。你的malloc實際上分配了一個比你的原始數組小的數組,因爲你沒有考慮到結尾的null。當你使用strcpy時,你寫了一個尾部爲null的分配數組的末尾。

由於您沒有包括與數據包結構相關的代碼,我不知道它是如何使用的,但如果之後有任何代碼需要C空終止的字符串,它可能不會按預期工作。

+0

感謝您的提示! – Sam

+1

'strcpy'不再是邪惡的,而是任何其他庫函數都是邪惡的。 ('strncpy'確實會將所有未使用的空間歸零)。問題是對所有需要的字符進行適當的計算,包括* nul-terminating *字符。 (這是區分* C字符串*和字符數組*的區別)。如果沒有* nul-terminating *字符,'strcpy'會很高興地繼續進入堆棧複製值,直到遇到第一個零偏'0'。用一個合適的* nul-terminated *字符串'strcpy'就完全沒問題。 –

相關問題