A userspace application that filters DHCP floods to protect a DHCP server. It uses the Netfilter userspace packet queuing API.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

perftest.pl 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #!/usr/bin/perl
  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. use strict;
  16. use IO::Socket::INET;
  17. use IO::Socket::INET6;
  18. use Time::HiRes qw(sleep);
  19. use warnings;
  20. $| = 1;
  21. my($clients, $leasetime, $floodclients, $floodpps, $dest, $destport) = @ARGV;
  22. usage() if !defined $destport;
  23. if ( $clients !~ /^\d+$/ || $clients < 1 ) {
  24. print STDERR "clients count must be a positive integer\n";
  25. exit 1;
  26. }
  27. if ( $leasetime !~ /^\d+$/ || $leasetime < 3 ) {
  28. print STDERR "leasetime must be at least 3\n";
  29. exit 1;
  30. }
  31. if ( $floodclients !~ /^\d+$/ || $floodclients < 0 ) {
  32. print STDERR "floodclients must be a 0 or more\n";
  33. exit 1;
  34. }
  35. if ( $floodpps !~ /^\d+$/ || $floodpps < 0 ) {
  36. print STDERR "floodpps must be 0 or more\n";
  37. exit 1;
  38. }
  39. if ( $dest !~ /^(\d+\.\d+\.\d+\.\d+)$/ && $dest !~ /^[0-9a-fA-F:]+$/ ) {
  40. print STDERR "destination IP must be a valid IPv4/IPv6 address\n";
  41. exit 1;
  42. }
  43. if ( $destport !~ /^\d+$/ || $destport < 1 || $destport > 65535 ) {
  44. print STDERR "destport must be between 1 and 65535\n";
  45. exit 1;
  46. }
  47. main($clients, $leasetime, $floodclients, $floodpps, $dest, $destport);
  48. sub usage {
  49. print STDERR <<EOF;
  50. ==============================================
  51. = DHCP Protect testing client =
  52. = This is only to test dhcp_protect =
  53. = DO NOT SEND THIS TO YOUR DHCP SERVER !!!! =
  54. ==============================================
  55. Usage: $0 <clients> <leasetime> <floodclients> <floodpps> <destination> <port>
  56. clients : number of 'normal' dhcp clients to simulator.
  57. leasetime : the desired leasetime.
  58. floodclients : number of client flood the server.
  59. floodpps : packet rate at which the floodclients flood the server (per client).
  60. destination : target IP address.
  61. port : targer UDP port.
  62. EOF
  63. exit 1;
  64. }
  65. sub main {
  66. my($clients, $leasetime, $floodclients, $floodpps, $dest, $destport)=@_;
  67. my $hdr = "";
  68. my $sock;
  69. if ( $dest =~ /:/ ) { # IPv6
  70. $sock = IO::Socket::INET6->new(
  71. Proto => 'udp',
  72. PeerAddr => $dest,
  73. PeerPort => $destport,
  74. );
  75. $hdr .= pack("H2", "01"); # msg-type
  76. $hdr .= pack("H6", "000000"); # transaction-id
  77. $hdr .= pack("C", 1); # DUID option
  78. $hdr .= pack("C", 6); # DUID length
  79. }
  80. else { # IPv4
  81. $sock = IO::Socket::INET->new(
  82. Proto => 'udp',
  83. PeerAddr => "$dest:$destport",
  84. );
  85. # pseudo packet, the only really relevant thing
  86. # is that option 82 is present and at the right place
  87. $hdr .= pack("H2","01"); # Opcode, bootrequest
  88. $hdr .= pack("H2","01"); # Hardware type, ethernet
  89. $hdr .= pack("H2","06"); # HW addr len, MAC = 6
  90. $hdr .= pack("H2","01"); # hops, 1 relay
  91. $hdr .= pack("H8","00000000"); # transaction ID
  92. $hdr .= pack("H4","0000"); # secs
  93. $hdr .= pack("H4","0000"); # flags
  94. $hdr .= pack("H8","00000000"); # ciaddr
  95. $hdr .= pack("H8","00000000"); # yiaddr
  96. $hdr .= pack("H8","00000000"); # siaddr
  97. $hdr .= pack("H8","00000000"); # giaddr
  98. $hdr .= pack("H32","0"x32); # cihwaddr
  99. $hdr .= pack("H128","0"x128); # hostname
  100. $hdr .= pack("H256","0"x256); # boot filename
  101. $hdr .= pack("H8","63825363"); # magic cookie
  102. $hdr .= pack("C", 82); # opt 82
  103. $hdr .= pack("C", 21); # opt 82 len
  104. $hdr .= pack("C", 1); # subopt 1 (circuitid)
  105. $hdr .= pack("C", 11); # subopt 1 len
  106. $hdr .= "Hello World";
  107. $hdr .= pack("C", 2); # subopt 2 (remoteid)
  108. $hdr .= pack("C", 6); # subopt 2 len (mac)
  109. }
  110. if ( $floodclients > 0 ) {
  111. my $pid = fork();
  112. # flood client
  113. if ( !$pid ) {
  114. my $int = 1/$floodpps/$floodclients;
  115. while(1) {
  116. for(my $i=0; $i<$floodclients; $i++) {
  117. my $pkt = $hdr;
  118. $pkt .= pack("H12", sprintf("66666666%04x", $i));
  119. $sock->send($pkt);
  120. sleep($int);
  121. }
  122. }
  123. exit;
  124. }
  125. }
  126. my $int = $leasetime/3/$clients;
  127. while(1) {
  128. for(my $i=0; $i<$clients; $i++) {
  129. my $pkt = $hdr;
  130. $pkt .= pack("H12", sprintf("00112233%04x",$i));
  131. $sock->send($pkt);
  132. sleep($int);
  133. }
  134. }
  135. }