diff options
author | Laszlo Attila Toth <panther@balabit.hu> | 2008-01-30 19:08:16 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-31 19:27:19 -0800 |
commit | 4a19ec5800fc3bb64e2d87c4d9fdd9e636086fe0 (patch) | |
tree | 610bd4e7dbcbdae25ba3806f4256745e98617825 /net | |
parent | 036c2e27bc3a6498afb35de017d810194032d765 (diff) |
[NET]: Introducing socket mark socket option.
A userspace program may wish to set the mark for each packets its send
without using the netfilter MARK target. Changing the mark can be used
for mark based routing without netfilter or for packet filtering.
It requires CAP_NET_ADMIN capability.
Signed-off-by: Laszlo Attila Toth <panther@balabit.hu>
Acked-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/sock.c | 11 | ||||
-rw-r--r-- | net/ipv4/ip_output.c | 3 | ||||
-rw-r--r-- | net/ipv4/raw.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 2 | ||||
-rw-r--r-- | net/ipv6/raw.c | 3 |
5 files changed, 21 insertions, 0 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index 1c4b1cd16d6..433715fb141 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -667,6 +667,13 @@ set_rcvbuf: else clear_bit(SOCK_PASSSEC, &sock->flags); break; + case SO_MARK: + if (!capable(CAP_NET_ADMIN)) + ret = -EPERM; + else { + sk->sk_mark = val; + } + break; /* We implement the SO_SNDLOWAT etc to not be settable (1003.1g 5.3) */ @@ -836,6 +843,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, case SO_PEERSEC: return security_socket_getpeersec_stream(sock, optval, optlen, len); + case SO_MARK: + v.val = sk->sk_mark; + break; + default: return -ENOPROTOOPT; } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 6e4d5f493bf..341779e685d 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -168,6 +168,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, } skb->priority = sk->sk_priority; + skb->mark = sk->sk_mark; /* Send it out. */ return ip_local_out(skb); @@ -385,6 +386,7 @@ packet_routed: (skb_shinfo(skb)->gso_segs ?: 1) - 1); skb->priority = sk->sk_priority; + skb->mark = sk->sk_mark; return ip_local_out(skb); @@ -1286,6 +1288,7 @@ int ip_push_pending_frames(struct sock *sk) iph->daddr = rt->rt_dst; skb->priority = sk->sk_priority; + skb->mark = sk->sk_mark; skb->dst = dst_clone(&rt->u.dst); if (iph->protocol == IPPROTO_ICMP) diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 85c08696abb..f863c3dc542 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -352,6 +352,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, skb_reserve(skb, hh_len); skb->priority = sk->sk_priority; + skb->mark = sk->sk_mark; skb->dst = dst_clone(&rt->u.dst); skb_reset_network_header(skb); @@ -544,6 +545,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, { struct flowi fl = { .oif = ipc.oif, + .mark = sk->sk_mark, .nl_u = { .ip4_u = { .daddr = daddr, .saddr = saddr, diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index cfe9e707883..9ac6ca2521c 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -257,6 +257,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, ipv6_addr_copy(&hdr->daddr, first_hop); skb->priority = sk->sk_priority; + skb->mark = sk->sk_mark; mtu = dst_mtu(dst); if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) { @@ -1439,6 +1440,7 @@ int ip6_push_pending_frames(struct sock *sk) ipv6_addr_copy(&hdr->daddr, final_dst); skb->priority = sk->sk_priority; + skb->mark = sk->sk_mark; skb->dst = dst_clone(&rt->u.dst); IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 4d880551fe6..d61c63dedbf 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -641,6 +641,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, skb_reserve(skb, hh_len); skb->priority = sk->sk_priority; + skb->mark = sk->sk_mark; skb->dst = dst_clone(&rt->u.dst); skb_put(skb, length); @@ -767,6 +768,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, */ memset(&fl, 0, sizeof(fl)); + fl.mark = sk->sk_mark; + if (sin6) { if (addr_len < SIN6_LEN_RFC2133) return -EINVAL; |