A userspace application that filters DHCP floods to protect a DHCP server. It uses the Netfilter userspace packet queuing API.
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

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. }