1/* 2 This is a module which is used for time matching 3 It is using some modified code from dietlibc (localtime() function) 4 that you can find at http://www.fefe.de/dietlibc/ 5 This file is distributed under the terms of the GNU General Public 6 License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL 7 2001-05-04 Fabrice MARIE <fabrice@netfilter.org> : initial development. 8 2001-21-05 Fabrice MARIE <fabrice@netfilter.org> : bug fix in the match code, 9 thanks to "Zeng Yu" <zengy@capitel.com.cn> for bug report. 10 2001-26-09 Fabrice MARIE <fabrice@netfilter.org> : force the match to be in 11 LOCAL_IN or PRE_ROUTING only. 12 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack, 13 added Nguyen Dang Phuoc Dong <dongnd@tlnet.com.vn> patch to support timezones. 14 2004-05-02 Fabrice : added support for date matching, from an idea of Fabien COELHO. 15*/ 16 17#include <linux/module.h> 18#include <linux/skbuff.h> 19#include <linux/netfilter/x_tables.h> 20#include <linux/netfilter_ipv4/ipt_time.h> 21#include <linux/time.h> 22 23MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>"); 24MODULE_DESCRIPTION("Match arrival timestamp/date"); 25MODULE_LICENSE("GPL"); 26 27struct tm 28{ 29 int tm_sec; /* Seconds. [0-60] (1 leap second) */ 30 int tm_min; /* Minutes. [0-59] */ 31 int tm_hour; /* Hours. [0-23] */ 32 int tm_mday; /* Day. [1-31] */ 33 int tm_mon; /* Month. [0-11] */ 34 int tm_year; /* Year - 1900. */ 35 int tm_wday; /* Day of week. [0-6] */ 36 int tm_yday; /* Days in year.[0-365] */ 37 int tm_isdst; /* DST. [-1/0/1]*/ 38 39 long int tm_gmtoff; /* we don't care, we count from GMT */ 40 const char *tm_zone; /* we don't care, we count from GMT */ 41}; 42 43static void 44localtime(const u32 time, struct tm *r); 45 46static int 47match(const struct sk_buff *skb, 48 const struct net_device *in, 49 const struct net_device *out, 50 const struct xt_match *match, 51 const void *matchinfo, 52 int offset, 53 unsigned int protoff, 54 int *hotdrop) 55{ 56 const struct ipt_time_info *info = matchinfo; /* match info for rule */ 57 struct tm currenttime; /* time human readable */ 58 struct timeval tv; 59 u_int8_t days_of_week[7] = {1, 2, 4, 8, 16, 32, 64}; 60 u_int16_t packet_time; 61 62 /* We might not have a timestamp, get one */ 63 tv = ktime_to_timeval(skb->tstamp); 64 if (tv.tv_sec == 0) { 65 __net_timestamp((struct sk_buff *)skb); 66 tv = ktime_to_timeval(skb->tstamp); 67 } 68 69 /* Transform the timestamp of the packet, in a human readable form */ 70 localtime(tv.tv_sec, ¤ttime); 71 72 /* check if we match this timestamp, we start by the days... */ 73 if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday]) 74 return 0; /* the day doesn't match */ 75 76 /* ... check the time now */ 77 packet_time = (currenttime.tm_hour * 600) + (currenttime.tm_min *60) + currenttime.tm_sec; 78 if ((packet_time < info->time_start) || (packet_time > info->time_stop)) 79 return 0; 80 81 /* here we match ! */ 82 return 1; 83} 84 85static int 86checkentry(const char *tablename, 87 const void *ip, 88 const struct xt_match *match, 89 void *matchinfo, 90 unsigned int hook_mask) 91{ 92 struct ipt_time_info *info = matchinfo; /* match info for rule */ 93 94 /* First, check that we are in the correct hooks */ 95 if (hook_mask 96 & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) 97 { 98 printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n"); 99 return 0; 100 } 101 102 /* Now check the coherence of the data ... */ 103 if ((info->time_start > 86399) || (info->time_stop > 86399)) 104 { 105 printk(KERN_WARNING "ipt_time: invalid argument\n"); 106 return 0; 107 } 108 109 return 1; 110} 111 112static struct xt_match time_match = { 113 .name = "time", 114 .family = AF_INET, 115 .match = match, 116 .matchsize = sizeof(struct ipt_time_info) + 8, 117 .checkentry = &checkentry, 118 .me = THIS_MODULE 119}; 120 121static int __init init(void) 122{ 123 return xt_register_match(&time_match); 124} 125 126static void __exit fini(void) 127{ 128 xt_unregister_match(&time_match); 129} 130 131module_init(init); 132module_exit(fini); 133 134 135/* The part below is borowed and modified from dietlibc */ 136 137/* seconds per day */ 138#define SPD 24*60*60 139 140static void 141localtime(const u32 time, struct tm *r) { 142 u32 i, timep; 143 extern struct timezone sys_tz; 144 const unsigned int __spm[12] = 145 { 0, 146 (31), 147 (31+28), 148 (31+28+31), 149 (31+28+31+30), 150 (31+28+31+30+31), 151 (31+28+31+30+31+30), 152 (31+28+31+30+31+30+31), 153 (31+28+31+30+31+30+31+31), 154 (31+28+31+30+31+30+31+31+30), 155 (31+28+31+30+31+30+31+31+30+31), 156 (31+28+31+30+31+30+31+31+30+31+30), 157 }; 158 register u32 work; 159 160 timep = time - (sys_tz.tz_minuteswest * 60); 161 work=timep%(SPD); 162 r->tm_sec=work%60; work/=60; 163 r->tm_min=work%60; r->tm_hour=work/60; 164 work=timep/(SPD); 165 r->tm_wday=(4+work)%7; 166 for (i=1970; ; ++i) { 167 register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365; 168 if (work>k) 169 work-=k; 170 else 171 break; 172 } 173 r->tm_year=i-1900; 174 for (i=11; i && __spm[i]>work; --i) ; 175 r->tm_mon=i; 176 r->tm_mday=work-__spm[i]+1; 177} 178