<?php
// 기본 환경 설정 파일 포함
include_once('./_common.php');
// ============================================================
// firewall.php - iptables 포트 관리 페이지
// ============================================================
session_start();
// ★ 접근 제한 (필요시 IP 체크 추가)
// if ($_SERVER['REMOTE_ADDR'] !== 'YOUR_IP') { http_response_code(403); exit; }
$message = '';
$msg_type = '';
// ============================================================
// POST 처리
// ============================================================
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
$port = (int)($_POST['port'] ?? 0);
$proto = in_array($_POST['proto'] ?? '', ['tcp','udp']) ? $_POST['proto'] : 'tcp';
$ip = trim($_POST['ip'] ?? '');
if ($port < 1 || $port > 65535) {
$message = '유효하지 않은 포트입니다.';
$msg_type = 'error';
} else {
if ($action === 'block') {
// 포트 차단
$cmd = "iptables -D INPUT -p {$proto} --dport {$port} -j ACCEPT 2>/dev/null; "
. "iptables -I INPUT 1 -p {$proto} --dport {$port} -j DROP 2>&1";
exec($cmd, $out, $ret);
$message = "포트 {$port}/{$proto} 차단 완료";
$msg_type = 'success';
} elseif ($action === 'open_all') {
// 전체 허용
$cmd = "iptables -D INPUT -p {$proto} --dport {$port} -j DROP 2>/dev/null; "
. "iptables -D INPUT -p {$proto} --dport {$port} -j ACCEPT 2>/dev/null; "
. "iptables -I INPUT 1 -p {$proto} --dport {$port} -j ACCEPT 2>&1";
exec($cmd, $out, $ret);
$message = "포트 {$port}/{$proto} 전체 허용";
$msg_type = 'success';
} elseif ($action === 'open_white') {
// 화이트IP만 허용
if (empty($ip) || !filter_var($ip, FILTER_VALIDATE_IP)) {
$message = '유효하지 않은 IP입니다.';
$msg_type = 'error';
} else {
// 기존 규칙 제거 후 화이트IP만 허용 + 나머지 DROP
$cmd = "iptables -D INPUT -p {$proto} --dport {$port} -j DROP 2>/dev/null; "
. "iptables -D INPUT -p {$proto} --dport {$port} -j ACCEPT 2>/dev/null; "
. "iptables -D INPUT -s {$ip} -p {$proto} --dport {$port} -j ACCEPT 2>/dev/null; "
. "iptables -I INPUT 1 -p {$proto} --dport {$port} -j DROP; "
. "iptables -I INPUT 1 -s {$ip} -p {$proto} --dport {$port} -j ACCEPT 2>&1";
exec($cmd, $out, $ret);
$message = "포트 {$port}/{$proto} → {$ip} 만 허용";
$msg_type = 'success';
}
} elseif ($action === 'delete') {
// 규칙 전체 삭제 (초기화)
$cmd = "iptables -D INPUT -p {$proto} --dport {$port} -j DROP 2>/dev/null; "
. "iptables -D INPUT -p {$proto} --dport {$port} -j ACCEPT 2>/dev/null; "
. "iptables -D INPUT -p {$proto} --dport {$port} -j ACCEPT 2>/dev/null 2>&1";
exec($cmd, $out, $ret);
$message = "포트 {$port}/{$proto} 규칙 삭제 (기본값 복원)";
$msg_type = 'success';
}
}
}
// ============================================================
// 현재 LISTEN 포트 목록 수집
// ============================================================
exec("ss -tlnp 2>/dev/null", $ss_out);
$listen_ports = [];
foreach ($ss_out as $line) {
if (!preg_match('/LISTEN/', $line)) continue;
// 포트 추출
if (preg_match('/:(\d+)\s/', $line, $m)) {
$p = (int)$m[1];
// 프로세스명 추출
$proc = '';
if (preg_match('/\("([^"]+)"/', $line, $pm)) $proc = $pm[1];
// 바인드 주소
$bind = 'all';
if (preg_match('/(\S+):' . $p . '/', $line, $bm)) {
$addr = $bm[1];
if ($addr !== '0.0.0.0' && $addr !== '*' && $addr !== '[::]' && $addr !== '::') {
$bind = $addr;
}
}
if (!isset($listen_ports[$p])) {
$listen_ports[$p] = ['port' => $p, 'proc' => $proc, 'bind' => $bind, 'proto' => 'tcp'];
}
}
}
ksort($listen_ports);
// ============================================================
// 현재 iptables 규칙 수집
// ============================================================
exec("iptables -L INPUT -n --line-numbers 2>/dev/null", $ipt_out);
$ipt_rules = [];
foreach ($ipt_out as $line) {
if (preg_match('/(\d+)\s+(ACCEPT|DROP|REJECT)\s+(\w+)\s+--\s+(\S+)\s+\S+.*dpt:(\d+)/', $line, $m)) {
$port_n = (int)$m[5];
$ipt_rules[$port_n][] = [
'num' => $m[1],
'target' => $m[2],
'proto' => $m[3],
'src' => $m[4],
];
}
}
// 포트별 상태 결정
function get_port_status($port, $ipt_rules) {
if (!isset($ipt_rules[$port])) return 'default'; // iptables 규칙 없음
foreach ($ipt_rules[$port] as $r) {
if ($r['target'] === 'DROP') return 'blocked';
if ($r['target'] === 'ACCEPT' && $r['src'] !== '0.0.0.0') return 'white';
if ($r['target'] === 'ACCEPT') return 'open';
}
return 'default';
}
function get_white_ip($port, $ipt_rules) {
if (!isset($ipt_rules[$port])) return '';
foreach ($ipt_rules[$port] as $r) {
if ($r['target'] === 'ACCEPT' && $r['src'] !== '0.0.0.0') return $r['src'];
}
return '';
}
// 헤더 부분 포함
include_once(G5_PATH.'/_head.php');
?>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>방화벽 포트 관리</title>
<link rel="stylesheet" type="text/css" href="./server_ports.css">
</head>
<body>
<div class="PageBox">
<h1><i class="fa-solid fa-shield-halved"></i> 방화벽 포트 관리 <span><?= date('Y-m-d H:i:s') ?></span></h1>
<?php if ($message): ?>
<div class="msg <?= $msg_type ?>">> <?= htmlspecialchars($message) ?></div>
<?php endif; ?>
<!-- ★ LISTEN 포트 목록 -->
<div class="section-title">현재 LISTEN 포트</div>
<table class="port-table">
<thead>
<tr>
<th>PORT</th>
<th>PROTO</th>
<th>PROCESS</th>
<th>BIND</th>
<th>STATUS</th>
<th>WHITE IP</th>
<th>ACTION</th>
</tr>
</thead>
<tbody>
<?php foreach ($listen_ports as $p => $info):
$status = get_port_status($p, $ipt_rules);
$white_ip = get_white_ip($p, $ipt_rules);
$status_label = match($status) {
'open' => '전체허용',
'blocked' => '차단',
'white' => '화이트IP',
default => '기본',
};
?>
<tr>
<td><strong><?= $p ?></strong></td>
<td><?= $info['proto'] ?></td>
<td><?= htmlspecialchars($info['proc']) ?></td>
<td><?= htmlspecialchars($info['bind']) ?></td>
<td><span class="badge <?= $status ?>"><?= $status_label ?></span></td>
<td><?= $white_ip ? htmlspecialchars($white_ip) : '-' ?></td>
<td>
<!-- 차단 -->
<form class="inline-form" method="post">
<input type="hidden" name="action" value="block">
<input type="hidden" name="port" value="<?= $p ?>">
<input type="hidden" name="proto" value="tcp">
<button type="submit" class="btn btn-block">차단</button>
</form>
<!-- 전체허용 -->
<form class="inline-form" method="post">
<input type="hidden" name="action" value="open_all">
<input type="hidden" name="port" value="<?= $p ?>">
<input type="hidden" name="proto" value="tcp">
<button type="submit" class="btn btn-open">전체허용</button>
</form>
<!-- 화이트IP -->
<button class="btn btn-white" onclick="toggleWhite(<?= $p ?>)">화이트IP</button>
<div class="white-form" id="wf_<?= $p ?>">
<form method="post" style="display:flex;gap:6px;align-items:center;">
<input type="hidden" name="action" value="open_white">
<input type="hidden" name="port" value="<?= $p ?>">
<input type="hidden" name="proto" value="tcp">
<input type="text" class="white-input" name="ip" placeholder="xxx.xxx.xxx.xxx" value="<?= htmlspecialchars($white_ip) ?>">
<button type="submit" class="btn btn-white">적용</button>
</form>
</div>
<!-- 규칙삭제 -->
<form class="inline-form" method="post">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="port" value="<?= $p ?>">
<input type="hidden" name="proto" value="tcp">
<button type="submit" class="btn btn-del">초기화</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<!-- ★ 포트 직접 추가 -->
<div class="add-section">
<h2>포트 직접 제어</h2>
<form method="post">
<div class="form-row">
<div class="form-group">
<label>PORT</label>
<input type="number" name="port" min="1" max="65535" placeholder="8080">
</div>
<div class="form-group">
<label>PROTO</label>
<select name="proto">
<option value="tcp">tcp</option>
<option value="udp">udp</option>
</select>
</div>
<div class="form-group">
<label>WHITE IP (화이트IP 선택시만)</label>
<input type="text" name="ip" placeholder="xxx.xxx.xxx.xxx">
</div>
<div class="form-group">
<label>ACTION</label>
<select name="action">
<option value="block">차단</option>
<option value="open_all">전체허용</option>
<option value="open_white">화이트IP만 허용</option>
<option value="delete">규칙삭제(초기화)</option>
</select>
</div>
<div class="form-group">
<label> </label>
<button type="submit" class="btn btn-open">실행</button>
</div>
</div>
</form>
</div>
<!-- ★ iptables 현재 상태 raw -->
<div class="section-title">iptables INPUT 현재 규칙</div>
<div class="raw-rules"><?php
exec("iptables -L INPUT -n --line-numbers -v 2>/dev/null", $raw);
echo htmlspecialchars(implode("\n", $raw));
?></div>
</div>
<script>
function toggleWhite(port) {
const el = document.getElementById('wf_' + port);
el.classList.toggle('active');
}
</script>
</body>
</html>
<?php require_once G5_PATH.'/_PAGE/tail.php'; ?>