📄 common.c
字号:
/************************************************************************* common.c** Implementation of user-space PPPoE redirector for Linux.** Common functions used by PPPoE client and server** Copyright (C) 2000 by Roaring Penguin Software Inc.** This program may be distributed according to the terms of the GNU* General Public License, version 2 or (at your option) any later version.** LIC: GPL************************************************************************/static char const RCSID[] ="$Id: common.c,v 1.19 2004/10/21 16:21:10 dfs Exp $";/* For vsnprintf prototype */#define _ISOC99_SOURCE 1/* For seteuid prototype */#define _BSD_SOURCE 1#include "pppoe.h"#ifdef HAVE_SYSLOG_H#include <syslog.h>#endif#include <string.h>#include <errno.h>#include <stdlib.h>#include <stdarg.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include <sys/types.h>#include <pwd.h>/* Are we running SUID or SGID? */int IsSetID = 0;static uid_t saved_uid = -2;static uid_t saved_gid = -2;/***********************************************************************%FUNCTION: parsePacket*%ARGUMENTS:* packet -- the PPPoE discovery packet to parse* func -- function called for each tag in the packet* extra -- an opaque data pointer supplied to parsing function*%RETURNS:* 0 if everything went well; -1 if there was an error*%DESCRIPTION:* Parses a PPPoE discovery packet, calling "func" for each tag in the packet.* "func" is passed the additional argument "extra".***********************************************************************/intparsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra){ UINT16_t len = ntohs(packet->length); unsigned char *curTag; UINT16_t tagType, tagLen; if (packet->ver != 1) { syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver); return -1; } if (packet->type != 1) { syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type); return -1; } /* Do some sanity checks on packet */ if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */ syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len); return -1; } /* Step through the tags */ curTag = packet->payload; while(curTag - packet->payload < len) { /* Alignment is not guaranteed, so do this by hand... */ tagType = (((UINT16_t) curTag[0]) << 8) + (UINT16_t) curTag[1]; tagLen = (((UINT16_t) curTag[2]) << 8) + (UINT16_t) curTag[3]; if (tagType == TAG_END_OF_LIST) { return 0; } if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) { syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen); return -1; } func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra); curTag = curTag + TAG_HDR_SIZE + tagLen; } return 0;}/***********************************************************************%FUNCTION: findTag*%ARGUMENTS:* packet -- the PPPoE discovery packet to parse* type -- the type of the tag to look for* tag -- will be filled in with tag contents*%RETURNS:* A pointer to the tag if one of the specified type is found; NULL* otherwise.*%DESCRIPTION:* Looks for a specific tag type.***********************************************************************/unsigned char *findTag(PPPoEPacket *packet, UINT16_t type, PPPoETag *tag){ UINT16_t len = ntohs(packet->length); unsigned char *curTag; UINT16_t tagType, tagLen; if (packet->ver != 1) { syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver); return NULL; } if (packet->type != 1) { syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type); return NULL; } /* Do some sanity checks on packet */ if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */ syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len); return NULL; } /* Step through the tags */ curTag = packet->payload; while(curTag - packet->payload < len) { /* Alignment is not guaranteed, so do this by hand... */ tagType = (((UINT16_t) curTag[0]) << 8) + (UINT16_t) curTag[1]; tagLen = (((UINT16_t) curTag[2]) << 8) + (UINT16_t) curTag[3]; if (tagType == TAG_END_OF_LIST) { return NULL; } if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) { syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen); return NULL; } if (tagType == type) { memcpy(tag, curTag, tagLen + TAG_HDR_SIZE); return curTag; } curTag = curTag + TAG_HDR_SIZE + tagLen; } return NULL;}/***********************************************************************%FUNCTION: switchToRealID*%ARGUMENTS:* None*%RETURNS:* Nothing*%DESCRIPTION:* Sets effective user-ID and group-ID to real ones. Aborts on failure***********************************************************************/voidswitchToRealID (void) { if (IsSetID) { if (saved_uid < 0) saved_uid = geteuid(); if (saved_gid < 0) saved_gid = getegid(); if (setegid(getgid()) < 0) { printErr("setgid failed"); exit(EXIT_FAILURE); } if (seteuid(getuid()) < 0) { printErr("seteuid failed"); exit(EXIT_FAILURE); } }}/***********************************************************************%FUNCTION: switchToEffectiveID*%ARGUMENTS:* None*%RETURNS:* Nothing*%DESCRIPTION:* Sets effective user-ID and group-ID back to saved gid/uid***********************************************************************/voidswitchToEffectiveID (void) { if (IsSetID) { if (setegid(saved_gid) < 0) { printErr("setgid failed"); exit(EXIT_FAILURE); } if (seteuid(saved_uid) < 0) { printErr("seteuid failed"); exit(EXIT_FAILURE); } }}/***********************************************************************%FUNCTION: dropPrivs*%ARGUMENTS:* None*%RETURNS:* Nothing*%DESCRIPTION:* If effective ID is root, try to become "nobody". If that fails and* we're SUID, switch to real user-ID***********************************************************************/voiddropPrivs(void){ struct passwd *pw = NULL; int ok = 0; if (geteuid() == 0) { pw = getpwnam("nobody"); if (pw) { if (setgid(pw->pw_gid) < 0) ok++; if (setuid(pw->pw_uid) < 0) ok++; } } if (ok < 2 && IsSetID) { setegid(getgid()); seteuid(getuid()); }}/***********************************************************************%FUNCTION: printErr*%ARGUMENTS:* str -- error message*%RETURNS:* Nothing*%DESCRIPTION:* Prints a message to stderr and syslog.***********************************************************************/voidprintErr(char const *str){ fprintf(stderr, "pppoe: %s\n", str); syslog(LOG_ERR, "%s", str);}/***********************************************************************%FUNCTION: strDup*%ARGUMENTS:* str -- string to copy*%RETURNS:* A malloc'd copy of str. Exits if malloc fails.***********************************************************************/char *strDup(char const *str){ char *copy = malloc(strlen(str)+1); if (!copy) { rp_fatal("strdup failed"); } strcpy(copy, str); return copy;}/***********************************************************************%FUNCTION: computeTCPChecksum*%ARGUMENTS:* ipHdr -- pointer to IP header* tcpHdr -- pointer to TCP header*%RETURNS:* The computed TCP checksum***********************************************************************/UINT16_tcomputeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr){ UINT32_t sum = 0; UINT16_t count = ipHdr[2] * 256 + ipHdr[3]; UINT16_t tmp; unsigned char *addr = tcpHdr; unsigned char pseudoHeader[12]; /* Count number of bytes in TCP header and data */ count -= (ipHdr[0] & 0x0F) * 4; memcpy(pseudoHeader, ipHdr+12, 8); pseudoHeader[8] = 0; pseudoHeader[9] = ipHdr[9]; pseudoHeader[10] = (count >> 8) & 0xFF; pseudoHeader[11] = (count & 0xFF); /* Checksum the pseudo-header */ sum += * (UINT16_t *) pseudoHeader; sum += * ((UINT16_t *) (pseudoHeader+2)); sum += * ((UINT16_t *) (pseudoHeader+4)); sum += * ((UINT16_t *) (pseudoHeader+6)); sum += * ((UINT16_t *) (pseudoHeader+8)); sum += * ((UINT16_t *) (pseudoHeader+10)); /* Checksum the TCP header and data */ while (count > 1) { memcpy(&tmp, addr, sizeof(tmp));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -