📄 devinet.c
字号:
}static struct notifier_block ip_netdev_notifier = { .notifier_call =inetdev_event,};static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, u32 pid, u32 seq, int event){ struct ifaddrmsg *ifm; struct nlmsghdr *nlh; unsigned char *b = skb->tail; nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm)); if (pid) nlh->nlmsg_flags |= NLM_F_MULTI; ifm = NLMSG_DATA(nlh); ifm->ifa_family = AF_INET; ifm->ifa_prefixlen = ifa->ifa_prefixlen; ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT; ifm->ifa_scope = ifa->ifa_scope; ifm->ifa_index = ifa->ifa_dev->dev->ifindex; if (ifa->ifa_address) RTA_PUT(skb, IFA_ADDRESS, 4, &ifa->ifa_address); if (ifa->ifa_local) RTA_PUT(skb, IFA_LOCAL, 4, &ifa->ifa_local); if (ifa->ifa_broadcast) RTA_PUT(skb, IFA_BROADCAST, 4, &ifa->ifa_broadcast); if (ifa->ifa_anycast) RTA_PUT(skb, IFA_ANYCAST, 4, &ifa->ifa_anycast); if (ifa->ifa_label[0]) RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label); nlh->nlmsg_len = skb->tail - b; return skb->len;nlmsg_failure:rtattr_failure: skb_trim(skb, b - skb->data); return -1;}static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb){ int idx, ip_idx; struct net_device *dev; struct in_device *in_dev; struct in_ifaddr *ifa; int s_ip_idx, s_idx = cb->args[0]; s_ip_idx = ip_idx = cb->args[1]; read_lock(&dev_base_lock); for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) { if (idx < s_idx) continue; if (idx > s_idx) s_ip_idx = 0; rcu_read_lock(); if ((in_dev = __in_dev_get(dev)) == NULL) { rcu_read_unlock(); continue; } for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; ifa = ifa->ifa_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0) { rcu_read_unlock(); goto done; } } rcu_read_unlock(); }done: read_unlock(&dev_base_lock); cb->args[0] = idx; cb->args[1] = ip_idx; return skb->len;}static void rtmsg_ifa(int event, struct in_ifaddr* ifa){ int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + 128); struct sk_buff *skb = alloc_skb(size, GFP_KERNEL); if (!skb) netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, ENOBUFS); else if (inet_fill_ifaddr(skb, ifa, 0, 0, event) < 0) { kfree_skb(skb); netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, EINVAL); } else { NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_IFADDR; netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV4_IFADDR, GFP_KERNEL); }}static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = { [4] = { .doit = inet_rtm_newaddr, }, [5] = { .doit = inet_rtm_deladdr, }, [6] = { .dumpit = inet_dump_ifaddr, }, [8] = { .doit = inet_rtm_newroute, }, [9] = { .doit = inet_rtm_delroute, }, [10] = { .doit = inet_rtm_getroute, .dumpit = inet_dump_fib, },#ifdef CONFIG_IP_MULTIPLE_TABLES [16] = { .doit = inet_rtm_newrule, }, [17] = { .doit = inet_rtm_delrule, }, [18] = { .dumpit = inet_dump_rules, },#endif};#ifdef CONFIG_SYSCTLvoid inet_forward_change(void){ struct net_device *dev; int on = ipv4_devconf.forwarding; ipv4_devconf.accept_redirects = !on; ipv4_devconf_dflt.forwarding = on; read_lock(&dev_base_lock); for (dev = dev_base; dev; dev = dev->next) { struct in_device *in_dev; rcu_read_lock(); in_dev = __in_dev_get(dev); if (in_dev) in_dev->cnf.forwarding = on; rcu_read_unlock(); } read_unlock(&dev_base_lock); rt_cache_flush(0);}static int devinet_sysctl_forward(ctl_table *ctl, int write, struct file* filp, void __user *buffer, size_t *lenp, loff_t *ppos){ int *valp = ctl->data; int val = *valp; int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); if (write && *valp != val) { if (valp == &ipv4_devconf.forwarding) inet_forward_change(); else if (valp != &ipv4_devconf_dflt.forwarding) rt_cache_flush(0); } return ret;}int ipv4_doint_and_flush(ctl_table *ctl, int write, struct file* filp, void __user *buffer, size_t *lenp, loff_t *ppos){ int *valp = ctl->data; int val = *valp; int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); if (write && *valp != val) rt_cache_flush(0); return ret;}int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context){ int *valp = table->data; int new; if (!newval || !newlen) return 0; if (newlen != sizeof(int)) return -EINVAL; if (get_user(new, (int __user *)newval)) return -EFAULT; if (new == *valp) return 0; if (oldval && oldlenp) { size_t len; if (get_user(len, oldlenp)) return -EFAULT; if (len) { if (len > table->maxlen) len = table->maxlen; if (copy_to_user(oldval, valp, len)) return -EFAULT; if (put_user(len, oldlenp)) return -EFAULT; } } *valp = new; rt_cache_flush(0); return 1;}static struct devinet_sysctl_table { struct ctl_table_header *sysctl_header; ctl_table devinet_vars[20]; ctl_table devinet_dev[2]; ctl_table devinet_conf_dir[2]; ctl_table devinet_proto_dir[2]; ctl_table devinet_root_dir[2];} devinet_sysctl = { .devinet_vars = { { .ctl_name = NET_IPV4_CONF_FORWARDING, .procname = "forwarding", .data = &ipv4_devconf.forwarding, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &devinet_sysctl_forward, }, { .ctl_name = NET_IPV4_CONF_MC_FORWARDING, .procname = "mc_forwarding", .data = &ipv4_devconf.mc_forwarding, .maxlen = sizeof(int), .mode = 0444, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_ACCEPT_REDIRECTS, .procname = "accept_redirects", .data = &ipv4_devconf.accept_redirects, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_SECURE_REDIRECTS, .procname = "secure_redirects", .data = &ipv4_devconf.secure_redirects, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_SHARED_MEDIA, .procname = "shared_media", .data = &ipv4_devconf.shared_media, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_RP_FILTER, .procname = "rp_filter", .data = &ipv4_devconf.rp_filter, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_SEND_REDIRECTS, .procname = "send_redirects", .data = &ipv4_devconf.send_redirects, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE, .procname = "accept_source_route", .data = &ipv4_devconf.accept_source_route, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_PROXY_ARP, .procname = "proxy_arp", .data = &ipv4_devconf.proxy_arp, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_MEDIUM_ID, .procname = "medium_id", .data = &ipv4_devconf.medium_id, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_BOOTP_RELAY, .procname = "bootp_relay", .data = &ipv4_devconf.bootp_relay, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_LOG_MARTIANS, .procname = "log_martians", .data = &ipv4_devconf.log_martians, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_TAG, .procname = "tag", .data = &ipv4_devconf.tag, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_ARPFILTER, .procname = "arp_filter", .data = &ipv4_devconf.arp_filter, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_ARP_ANNOUNCE, .procname = "arp_announce", .data = &ipv4_devconf.arp_announce, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_ARP_IGNORE, .procname = "arp_ignore", .data = &ipv4_devconf.arp_ignore, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_IPV4_CONF_NOXFRM, .procname = "disable_xfrm", .data = &ipv4_devconf.no_xfrm, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &ipv4_doint_and_flush, .strategy = &ipv4_doint_and_flush_strategy, }, { .ctl_name = NET_IPV4_CONF_NOPOLICY, .procname = "disable_policy", .data = &ipv4_devconf.no_policy, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &ipv4_doint_and_flush, .strategy = &ipv4_doint_and_flush_strategy, }, { .ctl_name = NET_IPV4_CONF_FORCE_IGMP_VERSION, .procname = "force_igmp_version", .data = &ipv4_devconf.force_igmp_version, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &ipv4_doint_and_flush, .strategy = &ipv4_doint_and_flush_strategy, }, }, .devinet_dev = { { .ctl_name = NET_PROTO_CONF_ALL, .procname = "all", .mode = 0555, .child = devinet_sysctl.devinet_vars, }, }, .devinet_conf_dir = { { .ctl_name = NET_IPV4_CONF, .procname = "conf", .mode = 0555, .child = devinet_sysctl.devinet_dev, }, }, .devinet_proto_dir = { { .ctl_name = NET_IPV4, .procname = "ipv4", .mode = 0555, .child = devinet_sysctl.devinet_conf_dir, }, }, .devinet_root_dir = { { .ctl_name = CTL_NET, .procname = "net", .mode = 0555, .child = devinet_sysctl.devinet_proto_dir, }, },};static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devconf *p){ int i; struct net_device *dev = in_dev ? in_dev->dev : NULL; struct devinet_sysctl_table *t = kmalloc(sizeof(*t), GFP_KERNEL); char *dev_name = NULL; if (!t) return; memcpy(t, &devinet_sysctl, sizeof(*t)); for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) { t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf; t->devinet_vars[i].de = NULL; } if (dev) { dev_name = dev->name; t->devinet_dev[0].ctl_name = dev->ifindex; } else { dev_name = "default"; t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT; } /* * Make a copy of dev_name, because '.procname' is regarded as const * by sysctl and we wouldn't want anyone to change it under our feet * (see SIOCSIFNAME). */ dev_name = net_sysctl_strdup(dev_name); if (!dev_name) goto free; t->devinet_dev[0].procname = dev_name; t->devinet_dev[0].child = t->devinet_vars; t->devinet_dev[0].de = NULL; t->devinet_conf_dir[0].child = t->devinet_dev; t->devinet_conf_dir[0].de = NULL; t->devinet_proto_dir[0].child = t->devinet_conf_dir; t->devinet_proto_dir[0].de = NULL; t->devinet_root_dir[0].child = t->devinet_proto_dir; t->devinet_root_dir[0].de = NULL; t->sysctl_header = register_sysctl_table(t->devinet_root_dir, 0); if (!t->sysctl_header) goto free_procname; p->sysctl = t; return; /* error path */ free_procname: kfree(dev_name); free: kfree(t); return;}static void devinet_sysctl_unregister(struct ipv4_devconf *p){ if (p->sysctl) { struct devinet_sysctl_table *t = p->sysctl; p->sysctl = NULL; unregister_sysctl_table(t->sysctl_header); kfree(t->devinet_dev[0].procname); kfree(t); }}#endifvoid __init devinet_init(void){ register_gifconf(PF_INET, inet_gifconf); register_netdevice_notifier(&ip_netdev_notifier); rtnetlink_links[PF_INET] = inet_rtnetlink_table;#ifdef CONFIG_SYSCTL devinet_sysctl.sysctl_header = register_sysctl_table(devinet_sysctl.devinet_root_dir, 0); devinet_sysctl_register(NULL, &ipv4_devconf_dflt);#endif}EXPORT_SYMBOL(devinet_ioctl);EXPORT_SYMBOL(in_dev_finish_destroy);EXPORT_SYMBOL(inet_select_addr);EXPORT_SYMBOL(inetdev_by_index);EXPORT_SYMBOL(register_inetaddr_notifier);EXPORT_SYMBOL(unregister_inetaddr_notifier);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -