A userspace application that filters DHCP floods to protect a DHCP server. It uses the Netfilter userspace packet queuing API.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

dp_nfqueue.c 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <arpa/inet.h>
  4. #include <errno.h>
  5. #include "dp_nfqueue.h"
  6. #include "dp_accounting.h"
  7. #include "dp_blacklist.h"
  8. #include "dp_helpers.h"
  9. #include "dp_dhcpv4.h"
  10. #include "dp_dhcpv6.h"
  11. // start netfilter queue
  12. void dp_nfq_start(dp_conf *conf) {
  13. struct nfq_handle *h;
  14. struct nfq_q_handle *qh;
  15. int fd;
  16. if ( ( h = nfq_open() ) == NULL ) {
  17. fprintf(stderr,"error during nfq_open() %s\n", strerror(errno));
  18. return;
  19. }
  20. if ( ( qh = nfq_create_queue(h, conf->queue, &dp_callback, conf) ) == NULL ) {
  21. fprintf(stderr, "error during nfq_create_queue() %s\n", strerror(errno));
  22. return;
  23. }
  24. if ( nfq_set_mode(qh, NFQNL_COPY_PACKET, 1500) < 0 ) {
  25. fprintf(stderr,"error during nfq_set_mode() %s\n", strerror(errno));
  26. return;
  27. }
  28. if ( nfq_set_queue_flags(qh, NFQA_CFG_F_FAIL_OPEN, NFQA_CFG_F_FAIL_OPEN) < 0 ) {
  29. fprintf(stderr,"error during nfq_set_queue_flags() %s\n", strerror(errno));
  30. return;
  31. }
  32. fd = nfq_fd(h);
  33. while(1) {
  34. static char buf[65536];
  35. int rv;
  36. rv = recv(fd, buf, sizeof(buf), 0);
  37. switch(rv) {
  38. case -1:
  39. fprintf(stderr, "recv() error: %s\n", strerror(errno));
  40. return;
  41. case 0:
  42. fprintf(stderr,"socket is closed!?\n");
  43. return;
  44. default:
  45. // send packet to callback
  46. nfq_handle_packet(h, buf, rv);
  47. break;
  48. }
  49. }
  50. }
  51. // decode dhcp packet
  52. int dp_dhcp_check(struct nfq_data *nfa, dp_conf *conf) {
  53. unsigned char *pkt;
  54. int pktlen;
  55. int offset = 0;
  56. unsigned char *remoteid = NULL;
  57. int remoteidlen = 0;
  58. int rv = NF_ACCEPT;
  59. pktlen = nfq_get_payload(nfa, &pkt);
  60. if ( conf->debug ) printf("got a packet, len = %i\n", pktlen);
  61. // can we read the IP proto and IP header length ?
  62. if ( pktlen > 0 ) {
  63. uint8_t ipver;
  64. uint8_t ihl;
  65. ipver = pkt[offset];
  66. ipver >>= 4;
  67. ihl = pkt[offset];
  68. ihl &= 0x0f;
  69. if ( ipver == 4 ) {
  70. // jump to DHCPv4
  71. offset += ( ihl * 4 ) + 8;
  72. dp_dhcpv4_check(conf, pkt, pktlen, offset, &remoteid, &remoteidlen);
  73. }
  74. else if ( ipver == 6 ) {
  75. // jump to DHCPv6
  76. offset += 40 + 8;
  77. dp_dhcpv6_check(conf, pkt, pktlen, offset, &remoteid, &remoteidlen);
  78. }
  79. else {
  80. if ( conf->debug ) printf("not an IPv4 packet\n");
  81. goto end;
  82. }
  83. }
  84. if ( conf->debug ) printf("remoteidlen=%i\n",remoteidlen);
  85. if ( remoteidlen>0 ) {
  86. if ( conf->debug ) {
  87. int i;
  88. printf("remoteid: ");
  89. for(i=0; i<remoteidlen; i++)
  90. printf("%02x", remoteid[i]);
  91. printf("\n");
  92. }
  93. // count the packet, even when blacklisted.
  94. dp_accounting_add(conf, remoteid, remoteidlen);
  95. // check if already in the blacklist
  96. if ( dp_blacklist_check(conf, remoteid, remoteidlen) == NF_DROP )
  97. rv = NF_DROP;
  98. // check if it must be added to the blacklist
  99. else if ( dp_accounting_check(conf, remoteid, remoteidlen) == NF_DROP ) {
  100. dp_blacklist_add(conf, remoteid, remoteidlen);
  101. rv = NF_DROP;
  102. }
  103. }
  104. end:
  105. dp_accounting_cleanup(conf);
  106. dp_blacklist_cleanup(conf);
  107. return rv;
  108. }
  109. // netfilter queue callback
  110. int dp_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) {
  111. struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(nfa);
  112. dp_conf *conf = (dp_conf*)data;
  113. int id = -1;
  114. int verdict;
  115. if ( ph ) {
  116. id = ntohl (ph->packet_id);
  117. if ( conf->debug ) printf ("received packet with id %d\n", id);
  118. }
  119. verdict = dp_dhcp_check(nfa, conf); /* Treat packet */
  120. // override decision for dryrun
  121. if ( conf->dryrun )
  122. verdict = NF_ACCEPT;
  123. return nfq_set_verdict(qh, id, verdict, 0, NULL); /* Verdict packet */
  124. }