Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ General Options:
-s enable silent mode
-w <file> write log to <file> instead of stderr

Port Filters:
-p <ports> comma-separated whitelist ports eq 53,80-1000
-P <ports> comma-separated blacklist ports eq 51820,51413

Advanced Options:
-f skip firewall rules
-g disable hop count estimation
Expand All @@ -45,7 +49,6 @@ Advanced Options:
-x <mask> set the mask for fwmark
-y <pct> raise TTL dynamically to <pct>% of estimated hops
-z use iptables commands instead of nft

```


Expand Down
4 changes: 3 additions & 1 deletion include/globvar.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
struct fs_context {
int exit;
FILE *logfp;
/* -b, -e, -h */ struct payload_info *plinfo;
/* -b, -u */ struct payload_info *plinfo;
/* -0 */ int inbound;
/* -1 */ int outbound;
/* -4 */ int use_ipv4;
Expand All @@ -48,6 +48,8 @@ struct fs_context {
/* -x */ uint32_t fwmask;
/* -y */ int dynamic_pct;
/* -z */ int use_iptables;
/* -p */ uint8_t *port_white;
/* -P */ uint8_t *port_black;
};

extern struct fs_context g_ctx;
Expand Down
31 changes: 31 additions & 0 deletions include/portmap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* portmap.h - FakeSIP: https://github.com/MikeWang000000/FakeSIP
*
* Copyright (C) 2025 MikeWang000000
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef FS_PORTMAP_H
#define FS_PORTMAP_H

#include <stdint.h>

int fs_portmap_get(const uint8_t *bitmap, uint16_t port);

void fs_portmap_set(uint8_t *bitmap, uint16_t port);

int fs_portmap_parse(uint8_t **bitmap_ptr, const char *spec);

#endif /* FS_PORTMAP_H */
4 changes: 3 additions & 1 deletion src/globvar.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ struct fs_context g_ctx = {.exit = 0,
/* -w */ .logpath = NULL,
/* -x */ .fwmask = 0,
/* -y */ .dynamic_pct = 0,
/* -z */ .use_iptables = 0};
/* -z */ .use_iptables = 0,
/* -p */ .port_white = NULL,
/* -P */ .port_black = NULL};
4 changes: 2 additions & 2 deletions src/ipv6ipt.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ int fs_ipt6_setup(void)
/*
drop time-exceeded ICMP packets
*/
{"iptables", "-w", "-t", "mangle", "-A", "FAKESIP_S", "-p", "icmp",
"--icmp-type", "11", "-j", "DROP", NULL},
{"ip6tables", "-w", "-t", "mangle", "-A", "FAKESIP_S", "-p", "icmpv6",
"--icmpv6-type", "3", "-j", "DROP", NULL},

/*
exclude non-GUA IPv6 addresses (from source)
Expand Down
39 changes: 38 additions & 1 deletion src/mainfun.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "rawsend.h"
#include "signals.h"
#include "srcinfo.h"
#include "portmap.h"

#ifndef PROGNAME
#define PROGNAME "fakesip"
Expand Down Expand Up @@ -73,6 +74,10 @@ static void print_usage(const char *name)
" -s enable silent mode\n"
" -w <file> write log to <file> instead of stderr\n"
"\n"
"Port Filters:\n"
" -p <ports> comma-separated whitelist ports eq 53,80-1000\n"
" -P <ports> comma-separated blacklist ports eq 51820,51413\n"
"\n"
"Advanced Options:\n"
" -f skip firewall rules\n"
" -g disable hop count estimation\n"
Expand Down Expand Up @@ -124,7 +129,7 @@ int main(int argc, char *argv[])

plinfo_cnt = iface_cnt = 0;

while ((opt = getopt(argc, argv, "0146ab:dfgi:km:n:r:st:u:w:x:y:z")) !=
while ((opt = getopt(argc, argv, "0146ab:dfgi:km:n:r:st:u:w:x:y:zp:P:")) !=
-1) {
switch (opt) {
case '0':
Expand Down Expand Up @@ -278,6 +283,30 @@ int main(int argc, char *argv[])
}
break;

case 'p':
case 'P': {
if (!optarg[0]) {
fprintf(stderr, "%s: value of -%c cannot be empty.\n",
argv[0], opt);
print_usage(argv[0]);
goto free_mem;
}

if (opt == 'p') {
if (fs_portmap_parse(&g_ctx.port_white, optarg) < 0) {
fprintf(stderr, "%s: invalid port spec for -p: %s\n",
argv[0], optarg);
goto free_mem;
}
} else {
if (fs_portmap_parse(&g_ctx.port_black, optarg) < 0) {
fprintf(stderr, "%s: invalid port spec for -P: %s\n",
argv[0], optarg);
goto free_mem;
}
}
} break;

case 'x':
tmp = strtoull(optarg, NULL, 0);
if (!tmp || tmp > UINT32_MAX) {
Expand Down Expand Up @@ -490,5 +519,13 @@ int main(int argc, char *argv[])
free(g_ctx.iface);
}

if (g_ctx.port_white) {
free(g_ctx.port_white);
}

if (g_ctx.port_black) {
free(g_ctx.port_black);
}

return exitcode;
}
99 changes: 99 additions & 0 deletions src/portmap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* portmap.c - FakeSIP: https://github.com/MikeWang000000/FakeSIP
*
* Copyright (C) 2025 MikeWang000000
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#define _GNU_SOURCE
#include "portmap.h"

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int fs_portmap_parse(uint8_t **bitmap_ptr, const char *spec)
{
char *sdup = NULL, *tok, *saveptr;
int ret = -1;

if (!spec || !spec[0]) {
return -1;
}

sdup = strdup(spec);
if (!sdup)
return -1;

for (tok = strtok_r(sdup, ",", &saveptr); tok;
tok = strtok_r(NULL, ",", &saveptr)) {
char *dash = strchr(tok, '-');
unsigned long start, end;
char *endptr;

if (!dash) {
start = strtoul(tok, &endptr, 0);
if (endptr == tok || *endptr != '\0' || start == 0 ||
start > 65535) {
goto out;
}
end = start;
} else {
*dash = '\0';
start = strtoul(tok, &endptr, 0);
if (endptr == tok || *endptr != '\0' || start == 0 ||
start > 65535) {
goto out;
}
end = strtoul(dash + 1, &endptr, 0);
if (endptr == dash + 1 || *endptr != '\0' || end == 0 ||
end > 65535) {
goto out;
}
if (start > end)
goto out;
}

if (!*bitmap_ptr) {
*bitmap_ptr = calloc(1, 8192);
if (!*bitmap_ptr)
goto out;
}

for (unsigned long p = start; p <= end; p++) {
fs_portmap_set(*bitmap_ptr, (uint16_t) p);
}
}

ret = 0;
out:
free(sdup);
return ret;
}

int fs_portmap_get(const uint8_t *bitmap, uint16_t port)
{
if (!bitmap)
return 0;
return (bitmap[port >> 3] & (uint8_t) (1u << (port & 7))) ? 1 : 0;
}

void fs_portmap_set(uint8_t *bitmap, uint16_t port)
{
if (!bitmap)
return;
bitmap[port >> 3] |= (uint8_t) (1u << (port & 7));
}
31 changes: 31 additions & 0 deletions src/rawsend.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "logging.h"
#include "payload.h"
#include "srcinfo.h"
#include "portmap.h"

#define NO_SNAT 0
#define NEED_SNAT 1
Expand Down Expand Up @@ -375,6 +376,36 @@ int fs_rawsend_handle(struct sockaddr_ll *sll, uint8_t *pkt_data, int pkt_len,
ipaddr_to_str(daddr, dst_ip_str);
}

/* Port whitelist/blacklist filtering: if whitelist is set, only process
packets where either source or dest port is in the whitelist. If any
port matches the blacklist, skip processing. */
{
uint16_t sport = ntohs(udph->source);
uint16_t dport = ntohs(udph->dest);

if (g_ctx.port_white) {
if (!(fs_portmap_get(g_ctx.port_white, sport) ||
fs_portmap_get(g_ctx.port_white, dport))) {
if (!g_ctx.silent) {
E_INFO("%s:%u ===(SKIP)=== %s:%u", src_ip_str, sport,
dst_ip_str, dport);
}
return NF_ACCEPT;
}
}

if (g_ctx.port_black) {
if (fs_portmap_get(g_ctx.port_black, sport) ||
fs_portmap_get(g_ctx.port_black, dport)) {
if (!g_ctx.silent) {
E_INFO("%s:%u ===(SKIP)=== %s:%u", src_ip_str, sport,
dst_ip_str, dport);
}
return NF_ACCEPT;
}
}
}

if (sll->sll_pkttype == PACKET_HOST) {
/*
Inbound UDP packet.
Expand Down