不需要开65535个“应用”,一个进程就够用了,想知道具体会发生什么可以直接自己试试,这是 Linux 上能运行的代码,编译要链接 libcap(-lcap),需要 root 运行或者给 CAP_NET_BIND_SERVICE#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/capability.h>
#include <sys/socket.h>
#include <unistd.h>
static bool check_capability() {
cap_t capabilities = cap_get_proc();
bool result = false;
do {
if (capabilities == NULL) {
perror("cap_get_proc");
exit(EXIT_FAILURE);
}
cap_flag_value_t value;
if (cap_get_flag(capabilities, CAP_NET_BIND_SERVICE, CAP_EFFECTIVE, &value) == -1) {
perror("cap_get_flag");
exit(EXIT_FAILURE);
}
if (value == CAP_SET) {
result = true;
break;
}
if (cap_get_flag(capabilities, CAP_NET_BIND_SERVICE, CAP_PERMITTED, &value) == -1) {
perror("cap_get_flag");
exit(EXIT_FAILURE);
}
if (value == CAP_CLEAR) {
result = false;
break;
}
cap_value_t caps[] = {CAP_NET_BIND_SERVICE};
if (cap_set_flag(capabilities, CAP_EFFECTIVE, 1, caps, CAP_SET) == -1) {
perror("cap_set_flag");
exit(EXIT_FAILURE);
}
if (cap_set_proc(capabilities) == -1) {
perror("cap_set_proc");
exit(EXIT_FAILURE);
}
result = true;
} while (false);
cap_free(capabilities);
return result;
}
static void deal_with_permission() {
if (geteuid() == 0) {
return;
}
if (check_capability() == false) {
}
if (check_capability() == false) {
fprintf(stderr, "permission denied.\n");
exit(EXIT_FAILURE);
}
}
static void handler(int sig) { return; }
int main() {
deal_with_permission();
int fds[UINT16_MAX + 1];
memset(fds, -1, sizeof(fds));
struct sockaddr_in address = {.sin_family = AF_INET, .sin_port = 0, .sin_addr = {inet_addr("127.0.0.1")}};
for (uint16_t i = 1; i != 0; i++) {
address.sin_port = htons(i);
fds[i] = socket(AF_INET, SOCK_STREAM, 0);
int ret = bind(fds[i], (struct sockaddr *)&address, sizeof(address));
if (ret == 0) {
printf("bind (fd)%d -> (port)%d\n", fds[i], i);
} else {
printf("failed to bind to (port)%d: %s\n", i, strerror(errno));
close(fds[i]);
fds[i] = -1;
}
}
signal(SIGINT, handler);
printf("signal me (pid=%d) with SIGINT to cleanup, waiting...\n", getpid());
pause();
for (uint16_t i = 1; i != 0; i++) {
if (fds[i] != -1) {
close(fds[i]);
}
}
return 0;
}
|