linux-old/net/ipv4/ip_masq_user.c
<<
>>
Prefs
   1/*
   2 *      IP_MASQ_USER user space control module
   3 *
   4 *
   5 *      $Id: ip_masq_user.c,v 1.1 1998/08/29 23:51:08 davem Exp $
   6 */
   7
   8#include <linux/config.h>
   9#include <linux/module.h>
  10#include <linux/types.h>
  11#include <linux/kernel.h>
  12#include <linux/errno.h>
  13#include <linux/skbuff.h>
  14#include <asm/system.h>
  15#include <linux/stat.h>
  16#include <linux/proc_fs.h>
  17#include <linux/in.h>
  18#include <linux/ip.h>
  19#include <linux/inet.h>
  20#include <linux/init.h>
  21#include <net/protocol.h>
  22#include <net/icmp.h>
  23#include <net/tcp.h>
  24#include <net/udp.h>
  25#include <net/checksum.h>
  26#include <net/ip_masq.h>
  27#include <net/ip_masq_mod.h>
  28#include <linux/sysctl.h>
  29#include <linux/ip_fw.h>
  30
  31#include <linux/ip_masq.h>
  32
  33/*
  34 *      Debug level
  35 */
  36static int debug=0;
  37
  38MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
  39MODULE_PARM(debug, "i");
  40
  41/*
  42static int check_5uple (struct ip_masq_user *ums) {
  43        return 0;
  44}
  45*/
  46static void masq_user_k2u(const struct ip_masq *ms, struct ip_masq_user *ums)
  47{
  48        ums->protocol = ms->protocol;
  49        ums->daddr = ms->daddr;
  50        ums->dport = ms->dport;
  51        ums->maddr = ms->maddr;
  52        ums->mport = ms->mport;
  53        ums->saddr = ms->saddr;
  54        ums->sport = ms->sport;
  55        ums->timeout = ms->timeout;
  56}
  57
  58
  59static int ip_masq_user_maddr(struct ip_masq_user *ums)
  60{
  61        struct device *dev;
  62        struct rtable *rt;
  63        int ret = -EINVAL;
  64        u32 rt_daddr, rt_saddr;
  65        u32 tos;
  66
  67        /*
  68         *      Did specify masq address.
  69         */
  70        if (ums->maddr)
  71                return 0;
  72
  73        /*
  74         *      Select address to use for routing query
  75         */
  76
  77        rt_daddr = ums->rt_daddr? ums->rt_daddr : ums->daddr;
  78        rt_saddr = ums->rt_saddr? ums->rt_saddr : ums->saddr;
  79
  80
  81        /*
  82         *      No address for routing, cannot continue
  83         */
  84        if (rt_daddr == 0) {
  85                IP_MASQ_DEBUG(1-debug, "cannot setup maddr with daddr=%lX, rt_addr=%lX\n",
  86                             ntohl(ums->daddr), ntohl(ums->rt_daddr));
  87                return -EINVAL;
  88        }
  89
  90        /*
  91         *      Find out rt device 
  92         */
  93
  94        rt_saddr = 0; 
  95        tos = RT_TOS(ums->ip_tos) | RTO_CONN;
  96
  97        if ((ret=ip_route_output(&rt, rt_daddr, rt_saddr, tos, 0 /* dev */))) {
  98                IP_MASQ_DEBUG(0-debug, "could not setup maddr for routing daddr=%lX, saddr=%lX\n",
  99                             ntohl(rt_daddr), ntohl(rt_saddr));
 100                return ret;
 101        }
 102        dev = rt->u.dst.dev;
 103        ums->maddr = ip_masq_select_addr(dev, rt->rt_gateway, RT_SCOPE_UNIVERSE);
 104
 105        IP_MASQ_DEBUG(1-debug, "did setup maddr=%lX\n", ntohl(ums->maddr));
 106        ip_rt_put(rt);
 107        return 0;
 108}
 109
 110/*
 111 *      Create new entry (from uspace)
 112 */
 113static int ip_masq_user_new(struct ip_masq_user *ums)
 114{
 115        struct ip_masq *ms = NULL;
 116        unsigned mflags = 0;
 117        int ret;
 118
 119        if (masq_proto_num (ums->protocol) == -1) {
 120                return EPROTONOSUPPORT;
 121        }
 122
 123        if (ums->dport == 0) {
 124                ums->flags |= IP_MASQ_USER_F_LISTEN;
 125        }
 126
 127        if (ums->flags | IP_MASQ_USER_F_LISTEN) {
 128                if ((ums->saddr == 0) || (ums->sport == 0)) {
 129                        return EINVAL;
 130                }
 131                mflags |= (IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);
 132
 133        }
 134
 135        if ((ret = ip_masq_user_maddr(ums)) < 0) {
 136                return -ret;
 137        }
 138
 139        mflags |= IP_MASQ_F_USER;
 140        ms = ip_masq_new(ums->protocol, 
 141                        ums->maddr, ums->mport, 
 142                        ums->saddr, ums->sport,
 143                        ums->daddr, ums->dport,
 144                        mflags);
 145        
 146        if (ms == NULL) {
 147                /*
 148                 *      FIXME: ip_masq_new() should return errno
 149                 */
 150                return EBUSY;
 151        }
 152
 153        /*
 154         *      Setup timeouts for this new entry
 155         */
 156
 157        if (ums->timeout) {
 158                ms->timeout = ums->timeout;
 159        } else if (ums->flags | IP_MASQ_USER_F_LISTEN) {
 160                ip_masq_listen(ms);
 161        }
 162
 163        masq_user_k2u(ms, ums);
 164        ip_masq_put(ms);
 165        return 0;
 166}
 167
 168/* 
 169 *      Delete existing entry
 170 */
 171static int ip_masq_user_del(struct ip_masq_user *ums)
 172{
 173        struct ip_masq *ms=NULL;
 174
 175        if (masq_proto_num (ums->protocol) == -1) {
 176                return EPROTONOSUPPORT;
 177        }
 178        start_bh_atomic();
 179        if (ums->mport && ums->maddr) {
 180                ms = ip_masq_in_get(ums->protocol, 
 181                                ums->daddr, ums->dport, 
 182                                ums->maddr, ums->mport);
 183                end_bh_atomic();
 184        } else if (ums->sport && ums->saddr) {
 185                ms = ip_masq_out_get(ums->protocol,
 186                                ums->saddr, ums->sport,
 187                                ums->daddr, ums->dport);
 188                end_bh_atomic();
 189        } else
 190                return EINVAL;  
 191        
 192        if (ms == NULL) {
 193                return ESRCH;
 194        }
 195
 196        /*
 197         *      got (locked) entry, setup almost tiny timeout :) and  
 198         *      give away
 199         *
 200         *      FIXME: should use something better than S_CLOSE
 201         */
 202        ms->timeout = IP_MASQ_S_CLOSE;
 203
 204        masq_user_k2u(ms, ums);
 205        ip_masq_put(ms);
 206        return 0;
 207}
 208
 209static struct ip_masq * ip_masq_user_locked_get (struct ip_masq_user *ums, int *err)
 210{
 211        struct ip_masq *ms=NULL;
 212        if (masq_proto_num (ums->protocol) == -1) {
 213                *err = EPROTONOSUPPORT;
 214        }
 215
 216        start_bh_atomic();
 217        if (ums->mport && ums->maddr) {
 218                ms = ip_masq_in_get(ums->protocol, 
 219                                ums->daddr, ums->dport, 
 220                                ums->maddr, ums->mport);
 221                end_bh_atomic();
 222        } else if (ums->sport && ums->saddr) {
 223                ms = ip_masq_out_get(ums->protocol,
 224                                ums->saddr, ums->sport,
 225                                ums->daddr, ums->dport);
 226                end_bh_atomic();
 227        } else
 228                *err = EINVAL;  
 229        
 230        if (ms == NULL) *err = ESRCH;
 231        return ms;
 232}
 233
 234/*
 235 *      Get existing entry (complete full tunnel info)
 236 */
 237static int ip_masq_user_get(struct ip_masq_user *ums)
 238{
 239        struct ip_masq *ms=NULL;
 240        int err;
 241
 242        ms = ip_masq_user_locked_get(ums, &err);
 243        if (ms == NULL)
 244                return err;
 245
 246        masq_user_k2u(ms, ums);
 247
 248        ip_masq_put(ms);
 249        return 0;
 250}
 251
 252/* 
 253 *      Set (some, valid) entry parameters
 254 */
 255static int ip_masq_user_set(struct ip_masq_user *ums)
 256{
 257        struct ip_masq *ms = NULL;
 258        int err;
 259
 260        ms = ip_masq_user_locked_get(ums, &err);
 261        if (ms == NULL)
 262                return err;
 263        
 264        /*
 265         *      FIXME: must allow selecting what you want to set
 266         */
 267        ms->timeout = ums->timeout;
 268
 269        masq_user_k2u(ms, ums);
 270        
 271        ip_masq_put(ms);
 272        return 0;
 273}
 274
 275
 276/*
 277 *      Entry point
 278 *      ret value:
 279 *              <0   err
 280 *              ==0  ok
 281 *              >0   ok, copy to user
 282 */
 283static int ip_masq_user_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
 284{
 285        struct ip_masq_user *ums = &mctl->u.user;
 286        int ret = EINVAL;
 287        int arglen = optlen - IP_MASQ_CTL_BSIZE;
 288        int cmd;
 289
 290        IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n",
 291                arglen,
 292                sizeof (*ums),
 293                optlen,
 294                sizeof (*mctl));
 295
 296        /*
 297         *      Yes, I'm a bad guy ...
 298         */
 299        if (arglen != sizeof(*ums) && optlen != sizeof(*mctl)) 
 300                return EINVAL;
 301
 302        MOD_INC_USE_COUNT;
 303
 304        /* 
 305         *      Don't trust the lusers - plenty of error checking! 
 306         */
 307        cmd = mctl->m_cmd;
 308        IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(cmd=%d)\n", cmd);
 309
 310        switch (mctl->m_cmd) {
 311                case IP_MASQ_CMD_ADD:
 312                case IP_MASQ_CMD_INSERT:
 313                        ret = ip_masq_user_new(ums);
 314                        break;
 315                case IP_MASQ_CMD_DEL:
 316                        ret = ip_masq_user_del(ums);
 317                        break;
 318                case IP_MASQ_CMD_SET:
 319                        ret = ip_masq_user_set(ums);
 320                        break;
 321                case IP_MASQ_CMD_GET:
 322                        ret = ip_masq_user_get(ums);
 323                        break;
 324        }
 325
 326        /*
 327         *      For all of the above, return masq tunnel info
 328         */
 329
 330        ret = -ret;
 331
 332        if (ret == 0) {
 333                ret = sizeof (*ums) + IP_MASQ_CTL_BSIZE;
 334                IP_MASQ_DEBUG(1-debug, "will return %d bytes to user\n", ret);
 335        }
 336
 337        MOD_DEC_USE_COUNT;
 338        return ret;
 339}
 340
 341
 342#ifdef CONFIG_PROC_FS
 343static int ip_masq_user_info(char *buffer, char **start, off_t offset,
 344                              int length, int proto)
 345{
 346        off_t pos=0, begin;
 347        struct ip_masq *ms;
 348        char temp[129];
 349        int idx = 0;
 350        int len=0;
 351        int magic_control;
 352
 353        MOD_INC_USE_COUNT;
 354
 355        IP_MASQ_DEBUG(1-debug, "Entered user_info with proto=%d\n", proto);
 356
 357        if (offset < 128)
 358        {
 359                sprintf(temp,
 360                        "Prot SrcIP    SPrt DstIP    DPrt MAddr    MPrt State        Flgs Ref Ctl Expires (free=%d,%d,%d)",
 361                        atomic_read(ip_masq_free_ports), 
 362                        atomic_read(ip_masq_free_ports+1), 
 363                        atomic_read(ip_masq_free_ports+2));
 364                len = sprintf(buffer, "%-127s\n", temp);
 365        }
 366        pos = 128;
 367
 368        for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
 369        {
 370        /*
 371         *      Lock is actually only need in next loop 
 372         *      we are called from uspace: must stop bh.
 373         */
 374        read_lock_bh(&__ip_masq_lock);
 375        for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link)
 376        {
 377                if (ms->protocol != proto) {
 378                        continue;
 379                }
 380
 381                pos += 128;
 382                if (pos <= offset) {
 383                        len = 0;
 384                        continue;
 385                }
 386
 387                /*
 388                 *      We have locked the tables, no need to del/add timers
 389                 *      nor cli()  8)
 390                 */
 391                
 392
 393                magic_control = atomic_read(&ms->n_control);
 394                if (!magic_control && ms->control) magic_control = -1;
 395                sprintf(temp,"%-4s %08lX:%04X %08lX:%04X %08lX:%04X %-12s %3X %4d %3d %7lu",
 396                        masq_proto_name(ms->protocol),
 397                        ntohl(ms->saddr), ntohs(ms->sport),
 398                        ntohl(ms->daddr), ntohs(ms->dport),
 399                        ntohl(ms->maddr), ntohs(ms->mport),
 400                        ip_masq_state_name(ms->state),
 401                        ms->flags,
 402                        atomic_read(&ms->refcnt),
 403                        magic_control,
 404                        (ms->timer.expires-jiffies)/HZ);
 405                len += sprintf(buffer+len, "%-127s\n", temp);
 406
 407                if(len >= length) {
 408                        read_unlock_bh(&__ip_masq_lock);
 409                        goto done;
 410                }
 411        }
 412        read_unlock_bh(&__ip_masq_lock);
 413        }
 414
 415done:
 416
 417        if (len) {
 418                begin = len - (pos - offset);
 419                *start = buffer + begin;
 420                len -= begin;
 421        }
 422        if(len>length)
 423                len = length;
 424        MOD_DEC_USE_COUNT;
 425        return len;
 426}
 427#else
 428#define ip_masq_user_info       NULL
 429#endif
 430
 431static struct ip_masq_hook ip_masq_user = {
 432        ip_masq_user_ctl,
 433        ip_masq_user_info
 434};
 435
 436int ip_masq_user_init(void)
 437{
 438        if (ip_masq_user_hook != NULL) 
 439                return -EEXIST;
 440        ip_masq_user_hook = &ip_masq_user;
 441        return 0;
 442}
 443
 444int ip_masq_user_done(void)
 445{
 446        if (ip_masq_user_hook == NULL) 
 447                return ENOENT;
 448        ip_masq_user_hook = NULL;
 449        return 0;
 450}
 451
 452#ifdef MODULE
 453EXPORT_NO_SYMBOLS;
 454int init_module(void)
 455{
 456        if (ip_masq_user_init() != 0)
 457                return -EIO;
 458        return 0;
 459}
 460
 461void cleanup_module(void)
 462{
 463        if (ip_masq_user_done() != 0)
 464                printk(KERN_INFO "ip_masq_user_done(): can't remove module");
 465}
 466
 467#endif /* MODULE */
 468
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.