diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62c8935 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ \ No newline at end of file diff --git a/files/k8s/deployments/diverter-bytecode-deployment-dns.yaml b/files/k8s/deployments/diverter-bytecode-deployment-dns.yaml new file mode 100644 index 0000000..a0d0d88 --- /dev/null +++ b/files/k8s/deployments/diverter-bytecode-deployment-dns.yaml @@ -0,0 +1,19 @@ +apiVersion: bpfd.dev/v1alpha1 +kind: XdpProgram +metadata: + labels: + app.kubernetes.io/name: xdpprogram + name: zfw-xdp-dns +spec: + bpffunctionname: xdp_filter + # Select all nodes + nodeselector: {} + interfaceselector: + interfaces: + - vethbe56455e + priority: 1 + proceedon: [pass,dispatcher_return] + bytecode: + image: + url: docker.io/elblag91/zfw-tc-ingress-bytecode:dns + imagepullpolicy: Always diff --git a/files/k8s/deployments/diverter-bytecode-deployment.yaml b/files/k8s/deployments/diverter-bytecode-deployment.yaml new file mode 100644 index 0000000..ac1f0d9 --- /dev/null +++ b/files/k8s/deployments/diverter-bytecode-deployment.yaml @@ -0,0 +1,141 @@ +apiVersion: bpfd.dev/v1alpha1 +kind: TcProgram +metadata: + labels: + app.kubernetes.io/name: tcprogram + name: zfw-tc-ingress-tproxy0 +spec: + bpffunctionname: tproxy0 + # Select all nodes + nodeselector: {} + interfaceselector: + interfaces: + - veth1b4ff726 + priority: 1 + direction: ingress + proceedon: [pipe,dispatcher_return] + bytecode: + image: + url: docker.io/elblag91/zfw-tc-ingress-bytecode:tproxy0 + imagepullpolicy: Always + mapownerselector: + matchLabels: + bpfd.dev/ownedByProgram: zfw-tc-ingress-tproxy5 +--- +apiVersion: bpfd.dev/v1alpha1 +kind: TcProgram +metadata: + labels: + app.kubernetes.io/name: tcprogram + name: zfw-tc-ingress-tproxy1 +spec: + bpffunctionname: tproxy1 + # Select all nodes + nodeselector: {} + interfaceselector: + interfaces: + - veth1b4ff726 + priority: 3 + direction: ingress + proceedon: [pipe,dispatcher_return] + bytecode: + image: + url: docker.io/elblag91/zfw-tc-ingress-bytecode:tproxy1 + imagepullpolicy: Always + mapownerselector: + matchLabels: + bpfd.dev/ownedByProgram: zfw-tc-ingress-tproxy5 +--- +apiVersion: bpfd.dev/v1alpha1 +kind: TcProgram +metadata: + labels: + app.kubernetes.io/name: tcprogram + name: zfw-tc-ingress-tproxy2 +spec: + bpffunctionname: tproxy2 + # Select all nodes + nodeselector: {} + interfaceselector: + interfaces: + - veth1b4ff726 + priority: 5 + direction: ingress + proceedon: [pipe,dispatcher_return] + bytecode: + image: + url: docker.io/elblag91/zfw-tc-ingress-bytecode:tproxy2 + imagepullpolicy: Always + mapownerselector: + matchLabels: + bpfd.dev/ownedByProgram: zfw-tc-ingress-tproxy5 +--- +apiVersion: bpfd.dev/v1alpha1 +kind: TcProgram +metadata: + labels: + app.kubernetes.io/name: tcprogram + name: zfw-tc-ingress-tproxy3 +spec: + bpffunctionname: tproxy3 + # Select all nodes + nodeselector: {} + interfaceselector: + interfaces: + - veth1b4ff726 + priority: 7 + direction: ingress + proceedon: [pipe,dispatcher_return] + bytecode: + image: + url: docker.io/elblag91/zfw-tc-ingress-bytecode:tproxy3 + imagepullpolicy: Always + mapownerselector: + matchLabels: + bpfd.dev/ownedByProgram: zfw-tc-ingress-tproxy5 +--- +apiVersion: bpfd.dev/v1alpha1 +kind: TcProgram +metadata: + labels: + app.kubernetes.io/name: tcprogram + name: zfw-tc-ingress-tproxy4 +spec: + bpffunctionname: tproxy4 + # Select all nodes + nodeselector: {} + interfaceselector: + interfaces: + - veth1b4ff726 + priority: 9 + direction: ingress + proceedon: [pipe,dispatcher_return] + bytecode: + image: + url: docker.io/elblag91/zfw-tc-ingress-bytecode:tproxy4 + imagepullpolicy: Always + mapownerselector: + matchLabels: + bpfd.dev/ownedByProgram: zfw-tc-ingress-tproxy5 +--- +apiVersion: bpfd.dev/v1alpha1 +kind: TcProgram +metadata: + labels: + app.kubernetes.io/name: tcprogram + name: zfw-tc-ingress-tproxy5 +spec: + bpffunctionname: tproxy5 + # Select all nodes + nodeselector: {} + interfaceselector: + interfaces: + - veth1b4ff726 + priority: 11 + direction: ingress + proceedon: [pipe,dispatcher_return] + bytecode: + image: + url: docker.io/elblag91/zfw-tc-ingress-bytecode:tproxy5 + imagepullpolicy: Always + \ No newline at end of file diff --git a/files/k8s/deployments/diverter-user-deployment copy.yaml b/files/k8s/deployments/diverter-user-deployment copy.yaml new file mode 100644 index 0000000..4b52a26 --- /dev/null +++ b/files/k8s/deployments/diverter-user-deployment copy.yaml @@ -0,0 +1,119 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: ziti +--- +# apiVersion: v1 +# kind: ConfigMap +# metadata: +# name: zfw-bin +# namespace: ziti +# binaryData: +# #kubectl create configmap zfw-bin -n ziti --from-file=./zfw +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kind-router01-sa + namespace: ziti +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: privileged-scc-tc +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:openshift:scc:privileged +subjects: +- kind: ServiceAccount + name: kind-router01 + namespace: ziti +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: kind-router01 + app.kubernetes.io/part-of: kind-router01 + app.kubernetes.io/managed-by: kind-router01 + name: bpfd-app-rolebinding-go-tc-counter +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: bpfd-bpfprogram-viewer-role +subjects: +- kind: ServiceAccount + name: kind-router01-sa + namespace: ziti +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: kind-router01-ds + namespace: ziti + labels: + k8s-app: kind-router01 +spec: + selector: + matchLabels: + name: kind-router01 + replicas: 1 + template: + metadata: + labels: + name: kind-router01 + spec: + nodeSelector: {} + hostNetwork: true + # hostNetwork: true + dnsPolicy: None + dnsConfig: + nameservers: + - 127.0.0.1 + - 1.1.1.1 + serviceAccountName: kind-router01-sa + tolerations: + # these tolerations are to have the daemonset runnable on control plane nodes + # remove them if your control plane nodes should not run pods + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: NoSchedule + - key: node-role.kubernetes.io/master + operator: Exists + effect: NoSchedule + containers: + - name: kind-router01 + image: elblag91/openziti-router + imagePullPolicy: Always + command: ["/bin/sh"] + args: ["-c", "while true; do echo hello; sleep 10;done"] + securityContext: + capabilities: + add: + - NET_ADMIN + env: + - name: NODENAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + volumeMounts: + - name: kind-router01-maps + mountPath: /run/tc/maps + - name: kind-router01-zfw + mountPath: /usr/local/bin/zfw + readOnly: true + volumes: + - name: kind-router01-maps + csi: + driver: csi.bpfd.dev + volumeAttributes: + csi.bpfd.dev/program: zfw-tc-ingress-tproxy5 + csi.bpfd.dev/maps: tc_stats_map + - name: kind-router01-zfw + configMap: + name: zfw-bin + defaultMode: 493 \ No newline at end of file diff --git a/files/k8s/deployments/diverter-user-deployment.yaml b/files/k8s/deployments/diverter-user-deployment.yaml new file mode 100644 index 0000000..391970c --- /dev/null +++ b/files/k8s/deployments/diverter-user-deployment.yaml @@ -0,0 +1,112 @@ + + apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + deployment.kubernetes.io/revision: "1" + meta.helm.sh/release-name: kind-router01 + meta.helm.sh/release-namespace: ziti + creationTimestamp: "2023-11-20T18:35:18Z" + generation: 1 + labels: + app.kubernetes.io/component: ziti-router + app.kubernetes.io/instance: kind-router01 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: ziti-router + app.kubernetes.io/version: 0.29.0 + helm.sh/chart: ziti-router-0.6.0 + name: kind-router01 + namespace: ziti + resourceVersion: "34257" + uid: 2a93f666-6645-479e-b5a2-4a7953be03fe +spec: + progressDeadlineSeconds: 600 + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app.kubernetes.io/component: ziti-router + app.kubernetes.io/instance: kind-router01 + app.kubernetes.io/name: ziti-router + strategy: + type: Recreate + template: + metadata: + creationTimestamp: null + labels: + app.kubernetes.io/component: ziti-router + app.kubernetes.io/instance: kind-router01 + app.kubernetes.io/name: ziti-router + spec: + hostNetwork: true + containers: + - args: + - /etc/ziti/config/ziti-router.yaml + command: + - ziti + - router + - run + env: + - name: ZITI_ROUTER_IDENTITY_DIR + value: /etc/ziti/identity + - name: PFXLOG_NO_JSON + value: "true" + image: docker.io/elblag91/openziti-router:latest + imagePullPolicy: Always + name: ziti-router + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - NET_TRANSPARENT + - NET_BIND_SERVICE + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /etc/ziti/identity + name: ziti-router-identity + readOnly: true + - mountPath: /etc/ziti/config + name: endpoints-data + - mountPath: /etc/ziti/config/ziti-router.yaml + name: ziti-router-config + subPath: ziti-router.yaml + - name: kind-router01-maps + mountPath: /run/tc/maps + - name: kind-router01-zfw + mountPath: /usr/local/bin/zfw + readOnly: true + dnsPolicy: None + dnsConfig: + nameservers: + - 127.0.0.1 + - 1.1.1.1 + restartPolicy: Always + schedulerName: default-scheduler + securityContext: + fsGroup: 2171 + terminationGracePeriodSeconds: 30 + volumes: + - name: ziti-router-identity + secret: + defaultMode: 292 + secretName: kind-router01-identity + - configMap: + defaultMode: 292 + name: kind-router01-config + name: ziti-router-config + - name: endpoints-data + persistentVolumeClaim: + claimName: kind-router01 + - name: kind-router01-maps + csi: + driver: csi.bpfd.dev + volumeAttributes: + csi.bpfd.dev/program: zfw-tc-ingress-tproxy5 + csi.bpfd.dev/maps: tcp_map,ifindex_ip_map,udp_map,matched_map,rb_map,diag_map,tun_map,zet_transp_map,zt_tproxy_map,ifindex_tun_map,tuple_count_map + - name: kind-router01-zfw + configMap: + name: zfw-bin + defaultMode: 493 \ No newline at end of file diff --git a/files/k8s/deployments/openzitirouter-sa.yaml b/files/k8s/deployments/openzitirouter-sa.yaml new file mode 100644 index 0000000..6a747ee --- /dev/null +++ b/files/k8s/deployments/openzitirouter-sa.yaml @@ -0,0 +1,42 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: + meta.helm.sh/release-name: kind-router01 + meta.helm.sh/release-namespace: ziti + labels: + app.kubernetes.io/managed-by: Helm + name: kind-router01-hook-serviceaccount + namespace: ziti +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: privileged-scc-tc +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:openshift:scc:privileged +subjects: + - kind: ServiceAccount + name: kind-router01-hook-serviceaccount + namespace: ziti +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: kind-router01 + app.kubernetes.io/part-of: kind-router01 + app.kubernetes.io/managed-by: kind-router01 + name: bpfd-app-rolebinding-kind-router01 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: bpfd-bpfprogram-viewer-role +subjects: + - kind: ServiceAccount + name: kind-router01-hook-serviceaccount + namespace: ziti \ No newline at end of file diff --git a/files/k8s/deployments/ziti-router-old.yaml b/files/k8s/deployments/ziti-router-old.yaml new file mode 100644 index 0000000..0432b1e --- /dev/null +++ b/files/k8s/deployments/ziti-router-old.yaml @@ -0,0 +1,22 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kind-router02 + labels: + app: kind-router02 + namespace: ziti +spec: + replicas: 1 + selector: + matchLabels: + app: kind-router02 + template: + metadata: + labels: + app: kind-router02 + spec: + containers: + - name: ziti-cli + image: openziti/ziti-cli + command: ["/bin/sh"] + args: ["-c", "while true; do echo hello; sleep 10;done"] diff --git a/files/k8s/deployments/ziti-router.yaml b/files/k8s/deployments/ziti-router.yaml new file mode 100644 index 0000000..173819b --- /dev/null +++ b/files/k8s/deployments/ziti-router.yaml @@ -0,0 +1,115 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: ziti + labels: + pod-security.kubernetes.io/enforce: baseline + pod-security.kubernetes.io/enforce-version: latest + pod-security.kubernetes.io/warn: baseline + pod-security.kubernetes.io/warn-version: latest +--- +# apiVersion: v1 +# kind: ConfigMap +# metadata: +# name: zfw-bin +# namespace: ziti +# binaryData: +# #kubectl create configmap zfw-bin -n ziti --from-file=./zfw +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kind-router01-sa + namespace: ziti +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: privileged-scc-tc +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:openshift:scc:privileged +subjects: +- kind: ServiceAccount + name: kind-router01 + namespace: ziti +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: kind-router01 + app.kubernetes.io/part-of: kind-router01 + app.kubernetes.io/managed-by: kind-router01 + name: bpfd-app-rolebinding-go-tc-counter +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: bpfd-bpfprogram-viewer-role +subjects: +- kind: ServiceAccount + name: kind-router01-sa + namespace: ziti +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: kind-router01-ds + namespace: ziti + labels: + k8s-app: kind-router01 +spec: + selector: + matchLabels: + name: kind-router01 + replicas: 1 + template: + metadata: + labels: + name: kind-router01 + spec: + nodeSelector: {} + # hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: kind-router01-sa + tolerations: + # these tolerations are to have the daemonset runnable on control plane nodes + # remove them if your control plane nodes should not run pods + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: NoSchedule + - key: node-role.kubernetes.io/master + operator: Exists + effect: NoSchedule + containers: + - name: kind-router01 + image: elblag91/openziti-router + imagePullPolicy: Always + command: ["/bin/sh"] + args: ["-c", "while true; do echo hello; sleep 10;done"] + securityContext: + runAsUser: 0 + env: + - name: NODENAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + volumeMounts: + - name: kind-router01-maps + mountPath: /run/bpfd/fs/maps + readOnly: true + - name: kind-router01-zfw + mountPath: /usr/local/bin/zfw + readOnly: true + volumes: + - name: kind-router01-maps + hostPath: + path: /run/bpfd/fs/maps + - name: kind-router01-zfw + configMap: + name: zfw-bin + defaultMode: 0755 \ No newline at end of file diff --git a/files/k8s/docker/cli/Dockerfile b/files/k8s/docker/cli/Dockerfile new file mode 100644 index 0000000..44cbf9d --- /dev/null +++ b/files/k8s/docker/cli/Dockerfile @@ -0,0 +1,65 @@ +# this Dockerfile builds docker.io/openziti/ziti-cli + +# get kubectl CLI from a source with Docker Content Trust (DCT) +# FIXME: require DCT at build time +FROM bitnami/kubectl as bitnami-kubectl + +# FIXME: This repo requires terms acceptance and is only available on registry.redhat.io. +# FROM registry.access.redhat.com/openshift4/ose-cli as openshift-cli + +FROM registry.access.redhat.com/ubi9/ubi-minimal +# This build stage grabs artifacts that are copied into the final image. +# It uses the same base as the final image to maximize docker cache hits. + +ARG ARTIFACTS_DIR=./release +ARG DOCKER_BUILD_DIR=. +# e.g. linux +ARG TARGETOS +# e.g. arm64 +ARG TARGETARCH + +ARG ZUID=2171 +ARG ZGID=2171 + +### Required OpenShift Labels +LABEL name="openziti/ziti-cli" \ + maintainer="developers@openziti.org" \ + vendor="NetFoundry" \ + summary="Run the OpenZiti CLI" \ + description="Run the OpenZiti CLI" + +USER root + +### install packages +RUN INSTALL_PKGS="python3.11 python3.11-pip tar bash-completion vim-minimal less shadow-utils jq" && \ + microdnf -y update --setopt=install_weak_deps=0 --setopt=tsflags=nodocs && \ + microdnf -y install --setopt=install_weak_deps=0 --setopt=tsflags=nodocs ${INSTALL_PKGS} + +### install OpenShift CLI (oc) +# FIXME: This repo requires terms acceptance and is only available on registry.redhat.io. +# COPY --from=openshift-cli /path/to/oc /usr/local/bin/oc + +### install Kubernetes CLI +COPY --from=bitnami-kubectl /opt/bitnami/kubectl/bin/kubectl /usr/local/bin/ + +### add license in the path prescribed by OpenShift +RUN mkdir -p -m0755 /licenses +COPY ./LICENSE /licenses/apache.txt + +RUN groupadd --gid ${ZGID} ziggy \ + && adduser --uid ${ZUID} --gid ${ZGID} --system --home /home/ziggy --shell /bin/bash ziggy \ + && mkdir -p /home/ziggy \ + && chown -R ${ZUID}:${ZGID} /home/ziggy \ + && chmod -R g+rwX /home/ziggy +RUN mkdir -p /usr/local/bin +COPY ${ARTIFACTS_DIR}/${TARGETARCH}/${TARGETOS}/ziti /usr/local/bin/ +RUN chmod 0755 /usr/local/bin/ziti + +RUN /usr/local/bin/ziti completion bash > /etc/bash_completion.d/ziti_cli + +COPY ${DOCKER_BUILD_DIR}/entrypoint.sh / +RUN chmod +x /entrypoint.sh +USER ziggy +COPY ${DOCKER_BUILD_DIR}/bashrc /home/ziggy/.bashrc +ENTRYPOINT [ "/entrypoint.sh" ] +CMD [ "ziti" ] \ No newline at end of file diff --git a/files/k8s/docker/cli/bashrc b/files/k8s/docker/cli/bashrc new file mode 100644 index 0000000..db6f7a8 --- /dev/null +++ b/files/k8s/docker/cli/bashrc @@ -0,0 +1,21 @@ +# this script addresses the problem of /etc/profile not being sourced +# because ziggy's BASH shell is not a "login shell." /etc/profile is +# intended to be sourced only once by the first shell, but it never runs +# automatically upon login because the first shell isn't invoked as a login +# shell. .bashrc runs for all interactive shells, so we can use it to +# replace the current shell process with a login shell. + +set -euo pipefail +USER="${USER:-$( id -u )}" +SHELL="${SHELL:-$( getent passwd "${USER}" | cut -d : -f 7 )}" +if [ -z "${SHELL}" ] ; then + echo 1>&2 "${0}: can't set SHELL; giving up" + exit 1 +fi +HOME="${HOME:-$( getent passwd "${USER}" | cut -d : -f 6 )}" +if [ -z "${HOME}" ] ; then + echo 1>&2 "${0}: can't set HOME; giving up" + exit 1 +fi +cd "${HOME}" +SHELL="${SHELL}" exec -a "-${SHELL##*/}" "${SHELL}" \ No newline at end of file diff --git a/files/k8s/docker/cli/entrypoint.sh b/files/k8s/docker/cli/entrypoint.sh new file mode 100644 index 0000000..b9ee09d --- /dev/null +++ b/files/k8s/docker/cli/entrypoint.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +exec ziti router "${@}" \ No newline at end of file diff --git a/files/k8s/docker/router/Dockerfile b/files/k8s/docker/router/Dockerfile new file mode 100644 index 0000000..39c1c00 --- /dev/null +++ b/files/k8s/docker/router/Dockerfile @@ -0,0 +1,22 @@ +ARG ZITI_CLI_TAG="latest" +ARG ZITI_CLI_IMAGE="docker.io/openziti/ziti-cli" +# this builds docker.io/openziti/ziti-router +FROM ${ZITI_CLI_IMAGE}:${ZITI_CLI_TAG} + +# This build stage grabs artifacts that are copied into the final image. +# It uses the same base as the final image to maximize docker cache hits. + +### Required OpenShift Labels +LABEL name="openziti/ziti-router" \ + maintainer="developers@openziti.org" \ + vendor="NetFoundry" \ + summary="Run the OpenZiti Router" \ + description="Run the OpenZiti Router" + +USER root + +COPY ./entrypoint.sh / +RUN chmod +x /entrypoint.sh +USER ziggy +ENTRYPOINT [ "/entrypoint.sh" ] +CMD [ "run" ] \ No newline at end of file diff --git a/files/k8s/docker/router/entrypoint.sh b/files/k8s/docker/router/entrypoint.sh new file mode 100644 index 0000000..b9ee09d --- /dev/null +++ b/files/k8s/docker/router/entrypoint.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +exec ziti router "${@}" \ No newline at end of file diff --git a/src/zfw.c b/src/zfw.c index 7dcb418..d5e344a 100644 --- a/src/zfw.c +++ b/src/zfw.c @@ -42,12 +42,12 @@ #include #ifndef BPF_MAX_ENTRIES -#define BPF_MAX_ENTRIES 100 // MAX # PREFIXES +#define BPF_MAX_ENTRIES 20 // MAX # PREFIXES #endif #define MAX_INDEX_ENTRIES 100 // MAX port ranges per prefix #define MAX_TABLE_SIZE 65536 // PORT Mapping table size #define MAX_IF_LIST_ENTRIES 3 -#define MAX_IF_ENTRIES 30 +#define MAX_IF_ENTRIES 40 #define MAX_ADDRESSES 10 #define IP_HEADER_TOO_BIG 1 #define NO_IP_OPTIONS_ALLOWED 2 @@ -73,6 +73,7 @@ #define TCP_CONNECTION_ESTABLISHED 10 #define CLIENT_FINAL_ACK_RCVD 11 #define CLIENT_INITIATED_UDP_SESSION 12 +#define MAP_ROOT_FS "/run/tc/maps/" bool add = false; bool delete = false; @@ -124,17 +125,17 @@ union bpf_attr tun_map; int tun_fd = -1; union bpf_attr rb_map; int rb_fd = -1; -const char *tproxy_map_path = "/sys/fs/bpf/tc/globals/zt_tproxy_map"; -const char *count_map_path = "/sys/fs/bpf/tc/globals/tuple_count_map"; -const char *diag_map_path = "/sys/fs/bpf/tc/globals/diag_map"; -const char *if_map_path = "/sys/fs/bpf/tc/globals/ifindex_ip_map"; -const char *matched_map_path = "/sys/fs/bpf/tc//globals/matched_map"; -const char *tcp_map_path = "/sys/fs/bpf/tc/globals/tcp_map"; -const char *udp_map_path = "/sys/fs/bpf/tc/globals/udp_map"; -const char *tun_map_path = "/sys/fs/bpf/tc/globals/tun_map"; -const char *if_tun_map_path = "/sys/fs/bpf/tc/globals/ifindex_tun_map"; -const char *transp_map_path = "/sys/fs/bpf/tc/globals/zet_transp_map"; -const char *rb_map_path = "/sys/fs/bpf/tc/globals/rb_map"; +const char *tproxy_map_path = MAP_ROOT_FS"/zt_tproxy_map"; +const char *count_map_path = MAP_ROOT_FS"/tuple_count_map"; +const char *diag_map_path = MAP_ROOT_FS"/diag_map"; +const char *if_map_path = MAP_ROOT_FS"/ifindex_ip_map"; +const char *matched_map_path = MAP_ROOT_FS"/matched_map"; +const char *tcp_map_path = MAP_ROOT_FS"/tcp_map"; +const char *udp_map_path = MAP_ROOT_FS"/udp_map"; +const char *tun_map_path = MAP_ROOT_FS"/tun_map"; +const char *if_tun_map_path = MAP_ROOT_FS"/ifindex_tun_map"; +const char *transp_map_path = MAP_ROOT_FS"/zet_transp_map"; +const char *rb_map_path = MAP_ROOT_FS"/rb_map"; char doc[] = "zfw -- ebpf firewall configuration tool"; const char *if_map_path; char *diag_interface; @@ -149,7 +150,7 @@ char *monitor_interface; char *tc_interface; char *object_file; char *direction_string; -const char *argp_program_version = "0.5.1"; +const char *argp_program_version = "0.6.0"; struct ring_buffer *ring_buffer; __u8 if_list[MAX_IF_LIST_ENTRIES]; @@ -493,7 +494,7 @@ char *nitoa(uint32_t address) } /* convert prefix string to __u16 */ -__u16 len2u16(char *len) +__u16 len2u16(char *len) { char *endPtr; int32_t tmpint = strtol(len, &endPtr, 10); @@ -1674,6 +1675,7 @@ void map_insert() printf("BPF_OBJ_GET: %s \n", strerror(errno)); exit(1); } + printf("insert: %d", fd); map.map_fd = fd; map.key = (uint64_t)&key; map.value = (uint64_t)&orule; @@ -1898,7 +1900,7 @@ void map_delete() { union bpf_attr count_map; /*path to pinned ifindex_ip_map*/ - const char *count_map_path = "/sys/fs/bpf/tc/globals/tuple_count_map"; + //const char *count_map_path = "/sys/fs/bpf/tc/globals/tuple_count_map"; memset(&count_map, 0, sizeof(count_map)); /* set path name with location of map in filesystem */ count_map.pathname = (uint64_t)count_map_path; @@ -1987,7 +1989,7 @@ void map_flush() close(fd); union bpf_attr count_map; /*path to pinned ifindex_ip_map*/ - const char *count_map_path = "/sys/fs/bpf/tc/globals/tuple_count_map"; + //const char *count_map_path = "/sys/fs/bpf/tc/globals/tuple_count_map"; memset(&count_map, 0, sizeof(count_map)); /* set path name with location of map in filesystem */ count_map.pathname = (uint64_t)count_map_path; @@ -2081,7 +2083,7 @@ int get_key_count() { union bpf_attr count_map; /*path to pinned ifindex_ip_map*/ - const char *count_map_path = "/sys/fs/bpf/tc/globals/tuple_count_map"; + //const char *count_map_path = count_map_path; memset(&count_map, 0, sizeof(count_map)); /* set path name with location of map in filesystem */ count_map.pathname = (uint64_t)count_map_path; diff --git a/src/zfw_tc_ingress.c b/src/zfw_tc_ingress.c index c889fbd..f868739 100644 --- a/src/zfw_tc_ingress.c +++ b/src/zfw_tc_ingress.c @@ -30,7 +30,7 @@ #include #ifndef BPF_MAX_ENTRIES -#define BPF_MAX_ENTRIES 100 //MAX # PREFIXES +#define BPF_MAX_ENTRIES 20 //MAX # PREFIXES #endif #define MAX_INDEX_ENTRIES 100 //MAX port ranges per prefix need to match in user space apps #define MAX_TABLE_SIZE 65536 //needs to match in userspace @@ -41,7 +41,7 @@ #define MATCHED_KEY_DEPTH 3 #define MATCHED_INT_DEPTH 50 #define MAX_IF_LIST_ENTRIES 3 -#define MAX_IF_ENTRIES 30 +#define MAX_IF_ENTRIES 40 #define SERVICE_ID_BYTES 32 #define MAX_TRANSP_ROUTES 256 #define BPF_MAX_SESSIONS 10000 @@ -219,12 +219,12 @@ struct transp_value{ }; struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(key_size, sizeof(struct transp_key)); - __uint(value_size,sizeof(struct transp_value)); - __uint(max_entries, BPF_MAX_ENTRIES); - __uint(pinning, LIBBPF_PIN_BY_NAME); - __uint(map_flags, BPF_F_NO_PREALLOC); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(struct transp_key)); + __uint(value_size,sizeof(struct transp_value)); + __uint(max_entries, BPF_MAX_ENTRIES); + __uint(map_flags, BPF_F_NO_PREALLOC); + __uint(pinning, LIBBPF_PIN_BY_NAME); } zet_transp_map SEC(".maps"); /*map to track up to 3 key matches per incoming packet search. Map is @@ -272,6 +272,7 @@ struct { __uint(pinning, LIBBPF_PIN_BY_NAME); } diag_map SEC(".maps"); + //map to keep track of total entries in zt_tproxy_map struct { __uint(type, BPF_MAP_TYPE_ARRAY); @@ -302,37 +303,37 @@ struct { * } */ struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(key_size, sizeof(struct tproxy_key)); - __uint(value_size,sizeof(struct tproxy_tuple)); - __uint(max_entries, BPF_MAX_ENTRIES); - __uint(pinning, LIBBPF_PIN_BY_NAME); - __uint(map_flags, BPF_F_NO_PREALLOC); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(struct tproxy_key)); + __uint(value_size,sizeof(struct tproxy_tuple)); + __uint(max_entries, BPF_MAX_ENTRIES); + __uint(map_flags, BPF_F_NO_PREALLOC); + __uint(pinning, LIBBPF_PIN_BY_NAME); } zt_tproxy_map SEC(".maps"); struct { - __uint(type, BPF_MAP_TYPE_LRU_HASH); - __uint(key_size, sizeof(struct tuple_key)); - __uint(value_size,sizeof(struct tcp_state)); - __uint(max_entries, BPF_MAX_SESSIONS); - __uint(pinning, LIBBPF_PIN_BY_NAME); + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(key_size, sizeof(struct tuple_key)); + __uint(value_size,sizeof(struct tcp_state)); + __uint(max_entries, BPF_MAX_SESSIONS); + __uint(pinning, LIBBPF_PIN_BY_NAME); } tcp_map SEC(".maps"); struct { - __uint(type, BPF_MAP_TYPE_LRU_HASH); - __uint(key_size, sizeof(struct tuple_key)); - __uint(value_size,sizeof(struct udp_state)); - __uint(max_entries, BPF_MAX_SESSIONS); - __uint(pinning, LIBBPF_PIN_BY_NAME); + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(key_size, sizeof(struct tuple_key)); + __uint(value_size,sizeof(struct udp_state)); + __uint(max_entries, BPF_MAX_SESSIONS); + __uint(pinning, LIBBPF_PIN_BY_NAME); } udp_map SEC(".maps"); /*Hashmap to track tun interface inbound passthrough connections*/ struct { - __uint(type, BPF_MAP_TYPE_LRU_HASH); - __uint(key_size, sizeof(struct tun_key)); - __uint(value_size,sizeof(struct tun_state)); - __uint(max_entries, BPF_MAX_SESSIONS); - __uint(pinning, LIBBPF_PIN_BY_NAME); + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(key_size, sizeof(struct tun_key)); + __uint(value_size,sizeof(struct tun_state)); + __uint(max_entries, BPF_MAX_SESSIONS); + __uint(pinning, LIBBPF_PIN_BY_NAME); } tun_map SEC(".maps"); /* function for ebpf program to access zt_tproxy_map entries @@ -629,8 +630,8 @@ static inline void iterate_masks(__u32 *mask, __u32 *exponent){ } //ebpf tc code entry program -SEC("action") -int bpf_sk_splice(struct __sk_buff *skb){ +SEC("classifier/tproxy0") +int tproxy0(struct __sk_buff *skb){ struct bpf_sock *sk; struct bpf_sock_tuple *tuple; int tuple_len; @@ -643,6 +644,8 @@ int bpf_sk_splice(struct __sk_buff *skb){ bool vrrp=false; int ret; + bpf_printk("Received packet in tproxy0"); + unsigned long long tstamp = bpf_ktime_get_ns(); struct bpf_event event = { tstamp, @@ -783,7 +786,7 @@ int bpf_sk_splice(struct __sk_buff *skb){ */ if(tcp){ /*if tcp based tuple implement stateful inspection to see if they were - * initiated by the local OS and If yes jump to assign. Then check if tuple is a reply to + initiated by the local OS and If yes jump to assign. Then check if tuple is a reply to outbound initiated from through the router interface. if not pass on to tproxy logic to determine if the openziti router has tproxy intercepts defined for the flow*/ event.proto = IPPROTO_TCP; @@ -791,7 +794,7 @@ int bpf_sk_splice(struct __sk_buff *skb){ if(sk){ if (sk->state != BPF_TCP_LISTEN){ if(local_diag->verbose){ - send_event(&event); + send_event(&event); //ingress event } goto assign; } @@ -949,12 +952,14 @@ int bpf_sk_splice(struct __sk_buff *skb){ /*Search for keys with Dest mask lengths from /32 down to /25 * and Source masks /32 down to /0 */ -SEC("action/1") -int bpf_sk_splice1(struct __sk_buff *skb){ +SEC("classifier/tproxy1") +int tproxy1(struct __sk_buff *skb){ struct bpf_sock_tuple *tuple; int tuple_len; int protocol; + bpf_printk("Got packet from tproxy0"); + /* find ethernet header from skb->data pointer */ struct ethhdr *eth = (struct ethhdr *)(unsigned long)(skb->data); @@ -1021,15 +1026,16 @@ int bpf_sk_splice1(struct __sk_buff *skb){ /*Search for keys with Dest mask lengths from /24 down to /17 * and Source masks /32 down to /0 */ -SEC("action/2") -int bpf_sk_splice2(struct __sk_buff *skb){ +SEC("classifier/tproxy2") +int tproxy2(struct __sk_buff *skb){ struct bpf_sock_tuple *tuple; int tuple_len; int protocol; + bpf_printk("Got packet from tproxy1"); + /* find ethernet header from skb->data pointer */ struct ethhdr *eth = (struct ethhdr *)(unsigned long)(skb->data); - /* check if incomming packet is a UDP or TCP tuple */ struct iphdr *iph = (struct iphdr *)(skb->data + sizeof(*eth)); @@ -1092,12 +1098,14 @@ int bpf_sk_splice2(struct __sk_buff *skb){ /*Search for keys with Dest mask lengths from /16 down to /9 * and Source masks /32 down to /0 */ -SEC("action/3") -int bpf_sk_splice3(struct __sk_buff *skb){ +SEC("classifier/tproxy3") +int tproxy3(struct __sk_buff *skb){ struct bpf_sock_tuple *tuple; int tuple_len; int protocol; + bpf_printk("Got packet from tproxy2"); + /* find ethernet header from skb->data pointer */ struct ethhdr *eth = (struct ethhdr *)(unsigned long)(skb->data); @@ -1162,12 +1170,14 @@ int bpf_sk_splice3(struct __sk_buff *skb){ /*Search for keys with Dest mask lengths from /8 down to /0 * and Source masks /32 down to /0 */ -SEC("action/4") -int bpf_sk_splice4(struct __sk_buff *skb){ +SEC("classifier/tproxy4") +int tproxy4(struct __sk_buff *skb){ struct bpf_sock_tuple *tuple; int tuple_len; int protocol; + bpf_printk("Got packet from tproxy3"); + /* find ethernet header from skb->data pointer */ struct ethhdr *eth = (struct ethhdr *)(unsigned long)(skb->data); @@ -1229,16 +1239,19 @@ int bpf_sk_splice4(struct __sk_buff *skb){ sexponent = 24; dexponent++; } + bpf_printk("tproxy4: no match made"); return TC_ACT_SHOT; } -SEC("action/5") -int bpf_sk_splice5(struct __sk_buff *skb){ +SEC("classifier/tproxy5") +int tproxy5(struct __sk_buff *skb){ struct bpf_sock *sk; int ret; struct bpf_sock_tuple *tuple,sockcheck = {0}; int tuple_len; + bpf_printk("Got packet from tproxy4"); + /*look up attached interface inbound diag status*/ struct diag_ip4 *local_diag = get_diag_ip4(skb->ingress_ifindex); if(!local_diag){ @@ -1337,7 +1350,7 @@ int bpf_sk_splice5(struct __sk_buff *skb){ bpf_sk_release(sk); return TC_ACT_SHOT; } - send_event(&event); + send_event(&event); //tproxy event goto assign; }else { diff --git a/src/zfw_xdp_dns_filter.c b/src/zfw_xdp_dns_filter.c new file mode 100644 index 0000000..1047d38 --- /dev/null +++ b/src/zfw_xdp_dns_filter.c @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef memcpy +#define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n)) +#endif +#define DNS_PORT 53 + +struct dns_name_struct { + char dns_name[255]; + __u8 dns_name_len; +}; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(key_size, sizeof(uint8_t)); + __uint(value_size, sizeof(struct dns_name_struct)); + __uint(max_entries, 100); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} dns_map SEC(".maps"); + +struct dns_question { + unsigned char qname[64]; + __u16 qtype; + __u16 qclass; +}; +/** \internal The DNS message header. */ +struct dnshdr { + __uint16_t id; + __uint8_t flags1, flags2; +#define DNS_FLAG1_RESPONSE 0x80 +#define DNS_FLAG1_OPCODE_STATUS 0x10 +#define DNS_FLAG1_OPCODE_INVERSE 0x08 +#define DNS_FLAG1_OPCODE_STANDARD 0x00 +#define DNS_FLAG1_AUTHORATIVE 0x04 +#define DNS_FLAG1_TRUNC 0x02 +#define DNS_FLAG1_RD 0x01 +#define DNS_FLAG2_RA 0x80 +#define DNS_FLAG2_ERR_MASK 0x0f +#define DNS_FLAG2_ERR_NONE 0x00 +#define DNS_FLAG2_ERR_NAME 0x03 + __uint16_t qdcount; + __uint16_t ancount; + __uint16_t nscount; + __uint16_t arcount; +}; +struct dns_question_section { + char qname[64]; + __uint16_t qtype; + __uint16_t qclass; +}; +/** \internal The resource record (i.e. answer, authority, additional sections) structure. */ +struct dns_resource_record { + /* DNS answer record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + char name[64]; + __uint16_t type; + __uint16_t class; + __uint16_t ttl[2]; + __uint16_t rdlength; + __uint8_t ipaddr[4]; +}; + +SEC("xdp") +int xdp_filter(struct xdp_md *ctx) { + + struct ethhdr *eth = (struct ethhdr *)(unsigned long)(ctx->data); + /* verify its a valid eth header within the packet bounds */ + if ((unsigned long)(eth + 1) > (unsigned long)ctx->data_end){ + return XDP_PASS; + } + + if (eth->h_proto != bpf_htons(ETH_P_IP)) { + return XDP_PASS; + } + + struct iphdr *iph = (struct iphdr *)(ctx->data + sizeof(*eth)); + /* ensure ip header is in packet bounds */ + if ((unsigned long)(iph + 1) > (unsigned long)ctx->data_end){ + return XDP_PASS; + } + + if (iph->protocol != IPPROTO_UDP) { + return XDP_PASS; + } + + struct udphdr *udph = (struct udphdr *)((unsigned long)iph + sizeof(*iph)); + if ((unsigned long)(udph + 1) > (unsigned long)ctx->data_end){ + return XDP_PASS; + } + + if (udph->dest != bpf_htons(DNS_PORT)) { + return XDP_PASS; + } + + struct dnshdr *dnsh = (struct dnshdr *)((unsigned long)udph + sizeof(*udph)); + if ((unsigned long)(dnsh + 1) > (unsigned long)ctx->data_end){ + return XDP_PASS; + } + + /* Calculate dns payload size */ + __u8 *dns_payload = (__u8 *)((unsigned long)dnsh + sizeof(*dnsh)); + if ((unsigned long)(dns_payload + 1) > (unsigned long)ctx->data_end) { + return XDP_PASS; + } + + int max_question_count = 1; + __u8 dns_name_len; + struct dns_name_struct *dns_name = NULL; + if ((dnsh->qdcount != 0) && (dnsh->ancount == 0) && (dnsh->nscount == 0) && (dnsh->arcount == 0)) { + for (int i = 0; i < max_question_count; i++) { + for (int j = 0; j < 255; j++) { + if ((unsigned long)(dns_payload + j + 1) > (unsigned long)ctx->data_end){ + return XDP_PASS; + } + if (*(dns_payload + j) == 0) { + dns_name_len = j+1; + break; + } + } + bpf_printk("completed %d ", dns_name_len); +// for (int j = 0; j < dns_name_len; j++) { +// bpf_printk("dns name is %c ", *(dns_payload + j)); +// } +// bpf_map_update_elem(&dns_map, &i, &dns_payload,0); +// memcpy(&dns_map,&dns_payload,dns_name_len); +// bpf_printk("completed2 %d ", dns_name_len); + dns_name = bpf_map_lookup_elem(&dns_map, &i); + long anwser = bpf_probe_read_str(&dns_name->dns_name, sizeof(dns_name->dns_name), dns_payload); + if (!anwser) { + return XDP_PASS; + } + + bpf_printk("completed2 %d ", dns_name_len); + } + } + return XDP_PASS; +} + +SEC("license") const char __license[] = "Dual BSD/GPL"; \ No newline at end of file