예제 #1
0
 /**
  * Determines the intersection between an IP (with optional prefix) and a
  * CIDR block.
  *
  * The IP will be checked against the CIDR block given and will either be
  * inside or outside the CIDR completely, or partially.
  *
  * NOTE: The caller should explicitly check against the INTERSECT_*
  * constants because this method will return a value > 1 even for partial
  * matches.
  *
  * @param mixed $ip The IP/cidr to match
  * @param mixed $cidr The CIDR block to match within
  * @return integer Returns an INTERSECT_* constant
  * @throws \InvalidArgumentException if either $ip or $cidr is invalid
  */
 public static function cidr_intersect($ip, $cidr)
 {
     // use fixed length HEX strings so we can easily do STRING comparisons
     // instead of using slower bccomp() math.
     $map = function ($v) {
         return sprintf("%032s", IP::inet_ptoh($v));
     };
     list($lo, $hi) = array_map($map, CIDR::cidr_to_range($ip));
     list($min, $max) = array_map($map, CIDR::cidr_to_range($cidr));
     /** visualization of logic used below
     			lo-hi   = $ip to check
     			min-max = $cidr block being checked against
     			--- --- --- lo  --- --- hi  --- --- --- --- --- IP/prefix to check
     			--- min --- --- max --- --- --- --- --- --- --- Partial "LOW" match
     			--- --- --- --- --- min --- --- max --- --- --- Partial "HIGH" match
     			--- --- --- --- min max --- --- --- --- --- --- No match "NO"
     			--- --- --- --- --- --- --- --- min --- max --- No match "NO"
     			min --- max --- --- --- --- --- --- --- --- --- No match "NO"
     			--- --- min --- --- --- --- max --- --- --- --- Full match "YES"
     		 */
     // IP is exact match or completely inside the CIDR block
     if ($lo >= $min and $hi <= $max) {
         return self::INTERSECT_YES;
     }
     // IP is completely outside the CIDR block
     if ($max < $lo or $min > $hi) {
         return self::INTERSECT_NO;
     }
     // @todo is it useful to return LOW/HIGH partial matches?
     // IP matches the lower end
     if ($max <= $hi and $min <= $lo) {
         return self::INTERSECT_LOW;
     }
     // IP matches the higher end
     if ($min >= $lo and $max >= $hi) {
         return self::INTERSECT_HIGH;
     }
     return self::INTERSECT_NO;
 }
예제 #2
0
 /**
  *
  */
 public function putMod(Request $request, Board $board, $post)
 {
     // Validate the request parameters.
     if (!($post = $this->validatePost($board, $post)) instanceof Post) {
         // If the response isn't a Post, it's a redirect or error.
         // Return the message.
         return $post;
     }
     // Take trailing arguments,
     // compare them against a list of real actions,
     // intersect the liss to find the true commands.
     $actions = ["delete", "ban", "all", "global"];
     $argList = func_get_args();
     $modActions = array_intersect($actions, array_splice($argList, 2));
     sort($modActions);
     $ban = in_array("ban", $modActions);
     $delete = in_array("delete", $modActions);
     $all = in_array("all", $modActions);
     $global = in_array("global", $modActions);
     if (!$ban) {
         return abort(404);
     }
     $validator = Validator::make(Input::all(), ['raw_ip' => 'required|boolean', 'ban_ip' => 'required_if:raw_ip,true|ip', 'ban_ip_range' => 'required|between:0,128', 'justification' => 'max:255', 'expires_days' => 'required|integer|min:0|max:' . $this->option('banMaxLength'), 'expires_hours' => 'required|integer|min:0|max:23', 'expires_minutes' => 'required|integer|min:0|max:59']);
     if (!$validator->passes()) {
         return redirect()->back()->withInput(Input::all())->withErrors($validator->errors());
     }
     $banLengthStr = [];
     $expiresDays = Input::get('expires_days');
     $expiresHours = Input::get('expires_hours');
     $expiresMinutes = Input::get('expires_minutes');
     if ($expiresDays > 0) {
         $banLengthStr[] = "{$expiresDays}d";
     }
     if ($expiresHours > 0) {
         $banLengthStr[] = "{$expiresHours}h";
     }
     if ($expiresMinutes > 0) {
         $banLengthStr[] = "{$expiresMinutes}m";
     }
     if ($expiresDays == 0 && $expiresHours == 0 && $expiresMinutes == 0) {
         $banLengthStr[] = "&Oslash;";
     }
     $banLengthStr = implode($banLengthStr, " ");
     // If we're banning without the ability to view IP addresses, we will get our address directly from the post in human-readable format.
     $banIpAddr = $this->user->canViewRawIP() ? Input::get('ban_ip') : $post->getAuthorIpAsString();
     // The CIDR is passed from our post parameters. By default, it is 32/128 for IPv4/IPv6 respectively.
     $banCidr = Input::get('ban_ip_range');
     // This generates a range from start to finish. I.E. 192.168.1.3/22 becomes [192.168.0.0, 192.168.3.255].
     // If we just pass the CDIR into the construct, we get 192.168.1.3-129.168.3.255 for some reason.
     $banCidrRange = CIDR::cidr_to_range("{$banIpAddr}/{$banCidr}");
     // We then pass this range into the construct method.
     $banIp = new CIDR($banCidrRange[0], $banCidrRange[1]);
     $ban = new Ban();
     $ban->ban_ip_start = inet_pton($banIp->getStart());
     $ban->ban_ip_end = inet_pton($banIp->getEnd());
     $ban->seen = false;
     $ban->created_at = $ban->freshTimestamp();
     $ban->updated_at = clone $ban->created_at;
     $ban->expires_at = clone $ban->created_at;
     $ban->expires_at->addDays($expiresDays);
     $ban->expires_at->addHours($expiresHours);
     $ban->expires_at->addMinutes($expiresMinutes);
     $ban->mod_id = $this->user->user_id;
     $ban->post_id = $post->post_id;
     $ban->ban_reason_id = null;
     $ban->justification = Input::get('justification');
     if ($global) {
         if ($ban && !$this->user->canBanGlobally() || $delete && !$this->user->canDeleteGlobally()) {
             return abort(403);
         }
         if ($ban) {
             $ban->board_uri = null;
             $ban->save();
         }
         $this->log('log.post.ban.global', $post, ["board_id" => $post->board_id, "board_uri" => $post->board_uri, "ip" => $post->getAuthorIpAsString(), "justification" => $ban->justification, "time" => $banLengthStr]);
         if ($delete) {
             $posts = Post::ipBinary($banIp);
             $this->log('log.post.ban.delete', $post, ["board_id" => $post->board_id, "board_uri" => $post->board_uri, "posts" => $posts->count()]);
             $posts->delete();
             return redirect($board->board_uri);
         }
     } else {
         if ($ban && !$board->canBan($this->user) || $delete && !$board->canDelete($this->user)) {
             return abort(403);
         }
         if ($ban) {
             $ban->board_uri = $post->board_uri;
             $ban->save();
         }
         $this->log('log.post.ban.local', $post, ["board_id" => $post->board_id, "board_uri" => $post->board_uri, "ip" => $post->getAuthorIpAsString(), "justification" => $ban->justification, "time" => $banLengthStr]);
         if ($delete) {
             if ($all) {
                 $posts = Post::ipBinary($banIp)->where('board_uri', $board->board_uri);
                 $this->log('log.post.ban.delete', $post, ["board_id" => $post->board_id, "board_uri" => $post->board_uri, "posts" => $posts->count()]);
                 $posts->delete();
                 return redirect($board->board_uri);
             } else {
                 $this->log('log.post.ban.delete', $post, ["board_id" => $post->board_id, "board_uri" => $post->board_uri, "posts" => 1]);
                 $post->delete();
                 if ($post->reply_to) {
                     return redirect("{$post->board_uri}/thread/{$post->op->board_id}");
                 } else {
                     return redirect($board->board_uri);
                 }
             }
         }
     }
     Event::fire(new PostWasBanned($post));
     Event::fire(new PostWasModerated($post, $this->user));
     if ($post->reply_to) {
         return redirect("{$post->board_uri}/thread/{$post->op->board_id}#{$post->board_id}");
     } else {
         return redirect("{$post->board_uri}/thread/{$post->board_id}");
     }
 }
예제 #3
0
 /**
  * Converts an IPv4 or IPv6 CIDR block into its range.
  *
  * @static
  * @param  string       $cidr CIDR block or IP address string.
  * @param  integer|null $bits If /bits is not specified on string they can be passed via this parameter instead.cidr_intersect
  * @return array  A 2 element array with the low, high range
  */
 public static function cidr_to_range($cidr, $bits = null)
 {
     if ($cidr instanceof static) {
         return parent::cidr_to_range($cidr->getCidr(), $bits);
     }
     return parent::cidr_to_range($cidr, $bits);
 }