A userspace application that filters DHCP floods to protect a DHCP server. It uses the Netfilter userspace packet queuing API.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

dp_nfqueue.c 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /**************************************************************************
  2. * Copyright 2019 Pascal Gloor
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. **************************************************************************/
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <arpa/inet.h>
  19. #include <errno.h>
  20. #include "dp_nfqueue.h"
  21. #include "dp_accounting.h"
  22. #include "dp_blacklist.h"
  23. #include "dp_helpers.h"
  24. #include "dp_dhcpv4.h"
  25. #include "dp_dhcpv6.h"
  26. // start netfilter queue
  27. void *dp_nfq_start(void *data) {
  28. dp_conf *conf = (dp_conf*)data;
  29. struct nfq_handle *h;
  30. struct nfq_q_handle *qh;
  31. int fd;
  32. if ( ( h = nfq_open() ) == NULL ) {
  33. fprintf(stderr,"error during nfq_open() %s\n", strerror(errno));
  34. return NULL;
  35. }
  36. if ( ( qh = nfq_create_queue(h, conf->queue, &dp_callback, conf) ) == NULL ) {
  37. fprintf(stderr, "error during nfq_create_queue() %s\n", strerror(errno));
  38. return NULL;
  39. }
  40. if ( nfq_set_mode(qh, NFQNL_COPY_PACKET, 1500) < 0 ) {
  41. fprintf(stderr,"error during nfq_set_mode() %s\n", strerror(errno));
  42. return NULL;
  43. }
  44. if ( nfq_set_queue_flags(qh, NFQA_CFG_F_FAIL_OPEN, NFQA_CFG_F_FAIL_OPEN) < 0 ) {
  45. fprintf(stderr,"error during nfq_set_queue_flags() %s\n", strerror(errno));
  46. return NULL;
  47. }
  48. fd = nfq_fd(h);
  49. while(1) {
  50. static char buf[65536];
  51. int rv;
  52. rv = recv(fd, buf, sizeof(buf), 0);
  53. switch(rv) {
  54. case -1:
  55. fprintf(stderr, "recv() error: %s\n", strerror(errno));
  56. return NULL;
  57. case 0:
  58. fprintf(stderr,"socket is closed!?\n");
  59. return NULL;
  60. default:
  61. // send packet to callback
  62. nfq_handle_packet(h, buf, rv);
  63. break;
  64. }
  65. }
  66. return NULL;
  67. }
  68. // decode dhcp packet
  69. int dp_dhcp_check(struct nfq_data *nfa, dp_conf *conf) {
  70. unsigned char *pkt;
  71. int pktlen;
  72. int offset = 0;
  73. unsigned char *remoteid = NULL;
  74. int remoteidlen = 0;
  75. int rv = NF_ACCEPT;
  76. pktlen = nfq_get_payload(nfa, &pkt);
  77. if ( conf->debug ) printf("got a packet, len = %i\n", pktlen);
  78. // can we read the IP proto and IP header length ?
  79. if ( pktlen > 0 ) {
  80. uint8_t ipver;
  81. uint8_t ihl;
  82. ipver = pkt[offset];
  83. ipver >>= 4;
  84. ihl = pkt[offset];
  85. ihl &= 0x0f;
  86. if ( ipver == 4 ) {
  87. // jump to DHCPv4
  88. offset += ( ihl * 4 ) + 8;
  89. dp_dhcpv4_check(conf, pkt, pktlen, offset, &remoteid, &remoteidlen);
  90. }
  91. else if ( ipver == 6 ) {
  92. // jump to DHCPv6
  93. offset += 40 + 8;
  94. dp_dhcpv6_check(conf, pkt, pktlen, offset, &remoteid, &remoteidlen);
  95. }
  96. else {
  97. if ( conf->debug ) printf("not an IPv4 packet\n");
  98. goto end;
  99. }
  100. }
  101. if ( conf->debug ) printf("remoteidlen=%i\n",remoteidlen);
  102. if ( remoteidlen>0 ) {
  103. if ( conf->debug ) {
  104. int i;
  105. printf("remoteid: ");
  106. for(i=0; i<remoteidlen; i++)
  107. printf("%02x", remoteid[i]);
  108. printf("\n");
  109. }
  110. // count the packet, even when blacklisted.
  111. dp_accounting_add(conf, remoteid, remoteidlen);
  112. // check if already in the blacklist
  113. if ( dp_blacklist_check(conf, remoteid, remoteidlen) == NF_DROP )
  114. rv = NF_DROP;
  115. // check if it must be added to the blacklist
  116. else if ( dp_accounting_check(conf, remoteid, remoteidlen) == NF_DROP ) {
  117. dp_blacklist_add(conf, remoteid, remoteidlen);
  118. rv = NF_DROP;
  119. }
  120. }
  121. end:
  122. return rv;
  123. }
  124. // netfilter queue callback
  125. int dp_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) {
  126. struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(nfa);
  127. dp_conf *conf = (dp_conf*)data;
  128. int id = -1;
  129. int verdict;
  130. if ( ph ) {
  131. id = ntohl (ph->packet_id);
  132. if ( conf->debug ) printf ("received packet with id %d\n", id);
  133. }
  134. verdict = dp_dhcp_check(nfa, conf); /* Treat packet */
  135. // override decision for dryrun
  136. if ( conf->dryrun )
  137. verdict = NF_ACCEPT;
  138. return nfq_set_verdict(qh, id, verdict, 0, NULL); /* Verdict packet */
  139. }