162306a36Sopenharmony_ci/* Copyright (c) 2016 Sargun Dhillon <sargun@sargun.me>
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or
462306a36Sopenharmony_ci * modify it under the terms of version 2 of the GNU General Public
562306a36Sopenharmony_ci * License as published by the Free Software Foundation.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include "vmlinux.h"
862306a36Sopenharmony_ci#include <string.h>
962306a36Sopenharmony_ci#include <linux/version.h>
1062306a36Sopenharmony_ci#include <bpf/bpf_helpers.h>
1162306a36Sopenharmony_ci#include <bpf/bpf_tracing.h>
1262306a36Sopenharmony_ci#include <bpf/bpf_core_read.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistruct {
1562306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
1662306a36Sopenharmony_ci	__type(key, struct sockaddr_in);
1762306a36Sopenharmony_ci	__type(value, struct sockaddr_in);
1862306a36Sopenharmony_ci	__uint(max_entries, 256);
1962306a36Sopenharmony_ci} dnat_map SEC(".maps");
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* kprobe is NOT a stable ABI
2262306a36Sopenharmony_ci * kernel functions can be removed, renamed or completely change semantics.
2362306a36Sopenharmony_ci * Number of arguments and their positions can change, etc.
2462306a36Sopenharmony_ci * In such case this bpf+kprobe example will no longer be meaningful
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * This example sits on a syscall, and the syscall ABI is relatively stable
2762306a36Sopenharmony_ci * of course, across platforms, and over time, the ABI may change.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_ciSEC("ksyscall/connect")
3062306a36Sopenharmony_ciint BPF_KSYSCALL(bpf_prog1, int fd, struct sockaddr_in *uservaddr,
3162306a36Sopenharmony_ci		 int addrlen)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	struct sockaddr_in new_addr, orig_addr = {};
3462306a36Sopenharmony_ci	struct sockaddr_in *mapped_addr;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	if (addrlen > sizeof(orig_addr))
3762306a36Sopenharmony_ci		return 0;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	if (bpf_probe_read_user(&orig_addr, sizeof(orig_addr), uservaddr) != 0)
4062306a36Sopenharmony_ci		return 0;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	mapped_addr = bpf_map_lookup_elem(&dnat_map, &orig_addr);
4362306a36Sopenharmony_ci	if (mapped_addr != NULL) {
4462306a36Sopenharmony_ci		memcpy(&new_addr, mapped_addr, sizeof(new_addr));
4562306a36Sopenharmony_ci		bpf_probe_write_user(uservaddr, &new_addr,
4662306a36Sopenharmony_ci				     sizeof(new_addr));
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci	return 0;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cichar _license[] SEC("license") = "GPL";
5262306a36Sopenharmony_ciu32 _version SEC("version") = LINUX_VERSION_CODE;
53