Segmentation Fault in EVP_DigestFinal_ex -> SHA256_Final due to NULL algctx - hash

using Linux (ubuntu 20.04) machine, openssl 3.0.7 is installed , running a sample code for signing.
we followed below procedure for signing. getting segmentation fault in EVP_DigestFinal_ex.
segmentation fault is happening due to mdctx->algctx=0x0. while debugging the code mdctx->algctx is updated in EVP_DigestInit_ex but latter it was freed in EVP_DigestSignInit. not sure what we are missing and how to update mdctx->algctx to avoid the crash.
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/provider.h>
EVP_PKEY *pkey = NULL;
generate_key(){
EVP_PKEY_CTX *ctx=NULL;
pkey=EVP_PKEY_new();
ctx=EVP_PKEY_CTX_new(pkey,NULL);
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (!ctx)
printf(" key gen failed");
if (EVP_PKEY_keygen_init(ctx) <= 0)
printf(" key gen failed");
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 512) <= 0)
printf(" key gen failed");
/* Generate key */
if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
printf(" key gen failed");
}
int main(int argc, char *argv[])
{
EVP_MD_CTX *mdctx;
const EVP_MD *m_md;
const EVP_MD *md;
EVP_PKEY *m_key;
EVP_PKEY *ed_pkey = NULL;
EVP_PKEY_CTX *ed_pctx = NULL;
// OSSL_PROVIDER *default;
size_t sign_len = 0;
u_int8_t m_sign_buf[2048];
int ret = 0;
char mess1[] = "Test Message\n";
char mess2[] = "Hello World\n";
unsigned char *outdigest = NULL;
unsigned int md_len = 0, i;
printf("args : %s\n",argv[1]);
//default = OSSL_PROVIDE_load(NULL, "default");
//md = EVP_get_digestbyname("SHA256");
//md = EVP_sha256();
md = EVP_MD_fetch(NULL, "SHA256", NULL); //;
if (md == NULL) {
printf("Unknown message digest %s\n", argv[1]);
exit(1);
}
generate_key();
printf("value of md %s\n",md);
mdctx = EVP_MD_CTX_new();
if((EVP_DigestInit_ex(mdctx, md, NULL)) != 1)
printf("EVP_DigestInit_ex failed \n");
if((EVP_DigestSignInit(mdctx, NULL, md, NULL, pkey)) != 1)
printf("EVP_DigestSignInit failed \n");
if((EVP_DigestSignUpdate(mdctx, mess1, strlen(mess1))) != 1)
printf("EVP_DigestSignUpdate failed \n");
//EVP_DigestUpdate(mdctx, mess2, strlen(mess2));
if((EVP_DigestSignFinal(mdctx, (u_int8_t*)NULL, &sign_len)) != 1)
printf("EVP_DigestSignFinal failed \n");
if((EVP_DigestSignFinal(mdctx, m_sign_buf, &sign_len)) != 1)
printf("EVP_DigestSignFinal 2 failed \n");
/* Allocate the output buffer */
outdigest = OPENSSL_malloc(EVP_MD_get_size(md));
if (outdigest == NULL)
printf("outdigest failed \n");
if((EVP_DigestFinal_ex(mdctx, outdigest, &md_len)) != 1)
printf("EVP_DigestFinal_ex failed \n");
EVP_MD_CTX_free(mdctx);
/* Print out the digest result */
BIO_dump_fp(stdout, outdigest, &md_len);
exit(0);
}
`
```
Thanks,
while debugging the code mdctx->algctx is updated in EVP_DigestInit_ex but latter it was freed in EVP_DigestSignInit. not sure what we are missing and how to update mdctx->algctx to avoid the crash.
CRASH Info:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7d99422 in SHA256_Final (md=0x5555555a88d0 "\250UUU\005", c=0x0)
    at ../openssl-3.0.7/include/crypto/md32_common.h:194
194         size_t n = c->num;
(gdb) bt
#0  0x00007ffff7d99422 in SHA256_Final (md=0x5555555a88d0 "\250UUU\005", c=0x0)
    at ../openssl-3.0.7/include/crypto/md32_common.h:194
#1  0x00007ffff7e2628c in sha256_internal_final (ctx=0x0, out=0x5555555a88d0 "\250UUU\005", outl=0x7fffffffda98,
    outsz=32) at ../openssl-3.0.7/providers/implementations/digests/sha2_prov.c:72
#2  0x00007ffff7cbadf6 in EVP_DigestFinal_ex (ctx=0x555555580d80, md=0x5555555a88d0 "\250UUU\005",
    isize=0x7fffffffdad8) at ../openssl-3.0.7/crypto/evp/digest.c:446
#3  0x000055555555575f in main (argc=1, argv=0x7fffffffe458) at test2.c:90

Related

How to get the audio stream from PJSIP when there is no audio hardware device

I want to use PJSIP's C API to record the incoming audio to a file on a machine with no hardware sound device .
I'm unsure about the details, but the sparse documentation for PJSIP suggests it should be
possible through the pjsua_set_null_snd_dev() call.
In the fully functioning (Windows biased) example below the call pjmedia_aud_dev_default_param(PJMEDIA_AUD_DEFAULT_CAPTURE_DEV, &param) returns PJMEDIA_AUD_INVALID_DEV in the status.
The code generates this same error on Linux (Ubuntu 14) and Windows 10 when there are no hardware audio devices present.
If there is an hardware audio device driver installed the exact same code works fine on both OSes.
I have compiled the PJSIP libraries with PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO enabled.
On Linux the presence of the module snd-dummy does not help.
How do I get access to the audio data stream from a SIP call after calling pjsua_set_null_snd_dev()?
#include <pjlib.h>
#include <pjlib-util.h>
#include <pjnath.h>
#include <pjsip.h>
#include <pjsip_ua.h>
#include <pjsip_simple.h>
#include <pjsua-lib/pjsua.h>
#include <pjmedia.h>
#include <pjmedia-codec.h>
#include <pj/log.h>
#include <pj/os.h>
int main(int, char **)
{
// Create pjsua first!
pj_status_t status = pjsua_create();
if (status != PJ_SUCCESS)
{
fprintf(stderr,"pjsua_create error\n");
return -1;
}
// Init pjsua
pjsua_config cfg;
pjsua_logging_config log_cfg;
pjsua_config_default(&cfg);
pjsua_logging_config_default(&log_cfg);
log_cfg.console_level = 4;
status = pjsua_init(&cfg, &log_cfg, NULL);
if (status != PJ_SUCCESS)
{
fprintf(stderr,"pjsua_init error\n");
return -1;
}
// Proactively list known audio devices so we are sure there are NONE
pjmedia_aud_dev_info info[64];
unsigned info_count = 64;
pjsua_enum_aud_devs(info, &info_count);
fprintf(stderr,"Listing known sound devices, total of [%u]\n", info_count);
for (unsigned i = 0; i<info_count; ++i)
{
fprintf(stderr,"Name [%s]", info[i].name);
}
// Add transport
pjsua_transport_config tcfg;
pjsua_transport_id trans_id;
pjsua_transport_config_default(&tcfg);
tcfg.port = 5060;
status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &tcfg, &trans_id);
if (status != PJ_SUCCESS)
{
fprintf(stderr, "pjsua_transport_create error\n");
return -1;
}
// Initialization is done, now start pjsua
status = pjsua_start();
if (status != PJ_SUCCESS)
{
fprintf(stderr, "pjsua_start error\n");
return -1;
}
// Set NULL sound
status = pjsua_set_null_snd_dev();
if (status != PJ_SUCCESS)
{
fprintf(stderr, "pjsua_set_null_snd_dev error");
return -1;
}
// Register to a SIP server by creating SIP account, I happen use use Asterisk
pjsua_acc_id acc_id;
fprintf(stderr, "Setting up SIP server registration\n");
{
pjsua_acc_config cfg;
pjsua_acc_config_default(&cfg);
cfg.id = pj_str("sip:6001#10.0.0.21");
cfg.reg_uri = cfg.id; // same as ID
cfg.cred_count = 1;
cfg.cred_info[0].realm = pj_str("*");
cfg.cred_info[0].scheme = pj_str("digest");
cfg.cred_info[0].username = pj_str("6001");
cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
cfg.cred_info[0].data = pj_str("teddy");
status = pjsua_acc_add(&cfg, PJ_TRUE, &acc_id);
if (status != PJ_SUCCESS)
{
fprintf(stderr, "pjsua_acc_add error\n");
return -1;
}
}
fprintf(stderr, "Waiting for SIP server registration to complete....\n");
Sleep(2000); // sleep 2 seconds
// Call extension 9 on my Asterisk server at 10.0.0.21:5060
pj_str_t sip_target(pj_str("sip:9#10.0.0.21"));
fprintf(stderr, "Making call to [%s]\n", sip_target.ptr);
pjsua_call_id call_id;
status = pjsua_call_make_call(acc_id, &sip_target, 0, NULL, NULL, &call_id);
if (status != PJ_SUCCESS)
{
fprintf(stderr, "pjsua_call_make_call error\n");
return -1;
}
pj_pool_t * pool = nullptr;
pjmedia_port * wav = nullptr;
pjmedia_aud_stream *strm = nullptr;
pool = pj_pool_create(pjmedia_aud_subsys_get_pool_factory(), "wav-audio", 1000, 1000, NULL);
if (nullptr == pool)
{
fprintf(stderr,"Pool creation failed\n");
return -1;
}
// 8kHz, single channel 16bit MS WAV format file
status = pjmedia_wav_writer_port_create(pool, "test.wav", 8000, 1, 320, 16, PJMEDIA_FILE_WRITE_PCM, 0, &wav);
if (status != PJ_SUCCESS)
{
fprintf(stderr, "Error creating WAV file\n");
return -1;
}
pjmedia_aud_param param;
//////////////////////////////////////////////////////
// FAILURE HERE : This is the function call which returns PJMEDIA_AUD_INVALID_DEV
//////////////////////////////////////////////////////
status = pjmedia_aud_dev_default_param(PJMEDIA_AUD_DEFAULT_CAPTURE_DEV, &param);
if (status != PJ_SUCCESS)
{
fprintf(stderr, "pjmedia_aud_dev_default_param()");
return -1;
}
param.dir = PJMEDIA_DIR_CAPTURE;
param.clock_rate = PJMEDIA_PIA_SRATE(&wav->info);
param.samples_per_frame = PJMEDIA_PIA_SPF(&wav->info);
param.channel_count = PJMEDIA_PIA_CCNT(&wav->info);
param.bits_per_sample = PJMEDIA_PIA_BITS(&wav->info);
status = pjmedia_aud_stream_create(&param, &test_rec_cb, &test_play_cb, wav, &strm);
if (status != PJ_SUCCESS)
{
fprintf(stderr, "Error opening the sound stream");
return -1;
}
status = pjmedia_aud_stream_start(strm);
if (status != PJ_SUCCESS)
{
fprintf(stderr, "Error starting the sound device");
return -1;
}
// Spend some time allowing the called party to pick up and recording to proceed
Sleep(10000); // sleep 10 seconds
// Clean up code omitted
return 0;
}
Apologies to the pure of heart for the mix of C and C++ above.
Solved this by loading the Alsa module snd-dummy.
Look in /lib/modules/YOUR_KERNEL_VERSION/modules.dep if its mentioned.
If you have it then load it with modprobe snd-dummy
Otherwise recompile your Kernel to include it as a module or follow the installation in the link above.

Unexpected staus with I2C on Raspberry Pi

I am writing c++ code (but my example is straight c) to talk to an AdaFruit Servo Motor Pi Hat, which uses the I2C bus to communicate with the Pi. I'm having a problem when trying to use the ioctl I2C_RDWR mechanism. I am getting a 'Bad Address' status back from the call. It doesn't matter what address I give it (the hat answers to 0x40, though), it always fails. I've boiled the code down into a short module, which is self contained. This is my first post to this site, so if I've done any faux pas, please forgive me.
When I run the attached code, I get the following response:
I2C_FUNC_I2C OK
I2C_FUNC_10BIT_ADDR
I2C_FUNC_PROTOCOL_MANGLING
I2C_FUNC_SMBUS_QUICK OK
I2C_FUNC_SMBUS_READ_BYTE OK
I2C_FUNC_SMBUS_WRITE_BYTE OK
I2C_FUNC_SMBUS_READ_BYTE_DATA OK
I2C_FUNC_SMBUS_WRITE_BYTE_DATA OK
I2C_FUNC_SMBUS_READ_WORD_DATA OK
I2C_FUNC_SMBUS_WRITE_WORD_DATA OK
I2C_FUNC_SMBUS_PROC_CALL OK
I2C_FUNC_SMBUS_READ_BLOCK_DATA
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA OK
I2C_FUNC_SMBUS_READ_I2C_BLOCK OK
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK OK
Write failed: Bad address
My Pi is a model B, version 2. I have enabled the i2c system and can see the i2c device:
crw-rw-rw- 1 root i2c 89, 1 Aug 31 23:02 i2c-1
Any help would be appreciated.
The code follows:
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
int main() {
int file;
int devAddr = 0x40;
int status;
uint32_t funcs;
uint8_t data = 0xAA;
struct i2c_rdwr_ioctl_data request;
struct i2c_msg ioctlMsg[1];
file = open("/dev/i2c-1", O_RDWR);
if(file < 0) {
perror("could not open device");
return 1;
}
status = ioctl(file, I2C_FUNCS, &funcs);
if(status < 0) {
perror("could not get funcs");
return 3;
}
fprintf(stderr, "\nI2C_FUNC_I2C ");
if ( I2C_FUNC_I2C & funcs) fprintf(stderr, "\t\t\t\tOK");
fprintf(stderr, "\nI2C_FUNC_10BIT_ADDR ");
if ( I2C_FUNC_10BIT_ADDR & funcs) fprintf(stderr, "\t\t\tOK");
fprintf(stderr, "\nI2C_FUNC_PROTOCOL_MANGLING ");
if ( I2C_FUNC_PROTOCOL_MANGLING & funcs) fprintf(stderr, "\tOK");
fprintf(stderr, "\nI2C_FUNC_SMBUS_QUICK ");
if ( I2C_FUNC_SMBUS_QUICK & funcs) fprintf(stderr, "\t\t\tOK");
fprintf(stderr, "\nI2C_FUNC_SMBUS_READ_BYTE ");
if ( I2C_FUNC_SMBUS_READ_BYTE & funcs) fprintf(stderr, "\t\tOK");
fprintf(stderr, "\nI2C_FUNC_SMBUS_WRITE_BYTE ");
if ( I2C_FUNC_SMBUS_WRITE_BYTE & funcs) fprintf(stderr, "\t\tOK");
fprintf(stderr, "\nI2C_FUNC_SMBUS_READ_BYTE_DATA ");
if ( I2C_FUNC_SMBUS_READ_BYTE_DATA & funcs) fprintf(stderr, "\t\tOK");
fprintf(stderr, "\nI2C_FUNC_SMBUS_WRITE_BYTE_DATA ");
if ( I2C_FUNC_SMBUS_WRITE_BYTE_DATA & funcs) fprintf(stderr, "\t\tOK");
fprintf(stderr, "\nI2C_FUNC_SMBUS_READ_WORD_DATA ");
if ( I2C_FUNC_SMBUS_READ_WORD_DATA & funcs) fprintf(stderr, "\t\tOK");
fprintf(stderr, "\nI2C_FUNC_SMBUS_WRITE_WORD_DATA ");
if ( I2C_FUNC_SMBUS_WRITE_WORD_DATA & funcs) fprintf(stderr, "\t\tOK");
fprintf(stderr, "\nI2C_FUNC_SMBUS_PROC_CALL ");
if ( I2C_FUNC_SMBUS_PROC_CALL & funcs) fprintf(stderr, "\t\tOK");
fprintf(stderr, "\nI2C_FUNC_SMBUS_READ_BLOCK_DATA ");
if ( I2C_FUNC_SMBUS_READ_BLOCK_DATA & funcs) fprintf(stderr, "\t\tOK");
fprintf(stderr, "\nI2C_FUNC_SMBUS_WRITE_BLOCK_DATA ");
if ( I2C_FUNC_SMBUS_WRITE_BLOCK_DATA & funcs) fprintf(stderr, "\tOK");
fprintf(stderr, "\nI2C_FUNC_SMBUS_READ_I2C_BLOCK ");
if ( I2C_FUNC_SMBUS_READ_I2C_BLOCK & funcs) fprintf(stderr, "\t\tOK");
fprintf(stderr, "\nI2C_FUNC_SMBUS_WRITE_I2C_BLOCK ");
if ( I2C_FUNC_SMBUS_WRITE_I2C_BLOCK & funcs) fprintf(stderr, "\t\tOK");
fprintf(stderr, "\n");
memset(ioctlMsg, 0, sizeof(struct i2c_rdwr_ioctl_data) * 2);
ioctlMsg[0].addr = 0x0;
ioctlMsg[0].flags = 0; /* write command */
ioctlMsg[0].len = 1;
ioctlMsg[0].buf = &data;
request.msgs = ioctlMsg;
request.nmsgs = 1;
status = ioctl(file, I2C_RDWR, request);
if(status < 0) {
perror("Write failed");
return 2;
}
close(file);
return 0;
}
I found my problem, turns out that the 'bad address' wasn't referring to the address of the I2C device, but the address of the block being sent in the ioctl command. I had forgotten to pass the address, as opposed to the value of the parameter in my call to ioctl.

gss_acquire_cred on Windows

I'm trying to acquire credentials for Administrator on Windows host.
I'm under mingw64_shell.
Here is my credential:
$ klist
Credentials cache: FILE:/tmp/krb5cc_1049076
Principal: Administrator#CORP.PEROKSID.COM
Issued Expires Principal
Jan 4 10:14:07 2016 Jan 4 20:14:07 2016 krbtgt/CORP.PEROKSID.COM#CORP.PEROKSID.COM
Here is my code:
#include <stdio.h>
#include <string.h>
#include <gss.h>
static void doDisplay(const char *m,OM_uint32 code,int type)
{
OM_uint32 maj_stat, min_stat;
gss_buffer_desc msg;
OM_uint32 msg_ctx;
msg_ctx = 0;
while (1)
{
maj_stat = gss_display_status(&min_stat, code,
type, GSS_C_NULL_OID,
&msg_ctx, &msg);
printf("GSS-API error %s - type: %s code: %d, msg: %s\n", m,
type == GSS_C_GSS_CODE ? "major" : "minor",
code,
(char *)msg.value);
gss_release_buffer(&min_stat, &msg);
if (!msg_ctx)
break;
}
}
void displayError(const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat)
{
doDisplay(msg, maj_stat, GSS_C_GSS_CODE);
doDisplay(msg, min_stat, GSS_C_MECH_CODE);
}
int getCreds(const char *service_name, gss_cred_id_t *server_creds)
{
printf ("Test name: %s\n", service_name);
gss_buffer_desc name_buf;
gss_name_t server_name;
OM_uint32 maj_stat, min_stat;
name_buf.value = service_name;
//name_buf.length = strlen(name_buf.value) + 1;
name_buf.length = strlen(name_buf.value);
maj_stat = gss_import_name(&min_stat, &name_buf,
(gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name);
if (maj_stat != GSS_S_COMPLETE)
{
displayError("importing name", maj_stat, min_stat);
return -1;
}
maj_stat = gss_acquire_cred(&min_stat, server_name, 0,
GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
server_creds, NULL, NULL);
if (maj_stat != GSS_S_COMPLETE)
{
displayError("acquiring credentials", maj_stat, min_stat);
return -1;
}
(void) gss_release_name(&min_stat, &server_name);
return 0;
}
int main(int argc, char** argv) {
gss_cred_id_t gsscreds;
if(getCreds(argv[1], &gsscreds) != 0)
return 1;
}
I have compiled it as a.exe. I run it:
$ ./a.exe 'Administrator#CORP.PEROKSID.COM'
Test name: Administrator#CORP.PEROKSID.COM
GSS-API error acquiring credentials - type: major code: 458752, msg: No credentials were supplied, or the credentials were unavailable or inaccessible
GSS-API error acquiring credentials - type: minor code: 11, msg: No principal in keytab matches desired name
How I can fix this error?
You probably misunderstood the API. The servername you are importing with GSS_C_NT_HOSTBASED_SERVICE is your target server. gss_acquire_cred needs an initiate crdential. accept is for servers/services. Services do work with keytabs only and client with caches or client keytabs. Since you have a valid credential cache for a user principal, you want to initiate a context with a client redential.

ICMP packet obsolete or malformed

I'm trying to use RAW sockets to create a ping program. The program I wrote however works only for localhost(127.0.0.1) and does not work for other IP addresses. While analyzing the generated packet in Wireshark, I get a message saying "Unknown ICMP (obsolete or malformed?)". It also tells me that the ICMP checksum is incorrect. I'm posting my code here
char source[20], destination[20];
struct sockaddr_in src, dst;
int addrlen= sizeof(src), recvSize, packetSize;
char *packet;
char *buffer;
struct iphdr* ip;
struct iphdr* ip_reply;
struct icmphdr* icmp;
unsigned short csum(unsigned short *, int);
char* getip();
int main(int argc, char* argv[]){
int pingSocket, optval;
struct protoent *protocol;
if(*(argv + 1) && (!(*(argv + 2)))){
//only one argument provided,assume it is the destination server
strncpy(destination, *(argv + 1), 15);
strncpy(source, getip(), 15);
}
inet_pton(AF_INET, destination, &(dst.sin_addr));
inet_pton(AF_INET, source, &(src.sin_addr));
protocol= getprotobyname("ICMP");
printf("Protocol number for ICMP is %d\n",protocol->p_proto);
pingSocket= socket(AF_INET, SOCK_RAW, protocol->p_proto); // Create socket
if(pingSocket< 0){
perror("Error creating socket: ");
exit(3);
}
printf("Socket created with identifier %d\n", pingSocket);
packetSize= sizeof(struct iphdr) + sizeof(struct icmphdr);
packet = (char *) malloc(packetSize);
buffer = (char *) malloc(packetSize);
ip= (struct iphdr*) packet;
icmp= (struct icmphdr*) (packet+ sizeof(struct iphdr));
memset(packet, 0, packetSize);
//Fill up the IP header
ip->ihl= 5;
ip->version= 4;
ip->tos= 0;
ip->tot_len = htons(packetSize);
ip->id = htons(0);
ip->frag_off= 0;
ip->ttl = 255;
ip->protocol= protocol->p_proto;
ip->saddr= src.sin_addr.s_addr;
ip->daddr= dst.sin_addr.s_addr;
setsockopt(pingSocket, protocol->p_proto, IP_HDRINCL, &optval, sizeof(int)); //HDRINCL to tell the kernel that the header is already included
icmp->type= ICMP_ECHO;
icmp->code= 0;
icmp->un.echo.id= rand();
icmp->un.echo.sequence= rand();
icmp->checksum= 0;
icmp->checksum = csum((unsigned short *)icmp, sizeof(struct icmphdr));
dst.sin_family= AF_INET;
sendto(pingSocket, packet, packetSize, 0, (struct sockaddr *)&dst, sizeof(dst));
printf("Sent ping request with size %d to %s\n", ip->tot_len, destination);
printf("Request's IP ID: %d and IP TTL: %d\n", ip->id, ip->ttl);
printf("Packet: \n%s\n", packet);
// Wait for response
if( (recvSize= recvfrom(pingSocket, buffer, sizeof(struct iphdr)+sizeof(struct icmphdr), 0, (struct sockaddr *)&dst, &addrlen)) < 0){
perror("Receive error: ");
}
else{
printf("Received a reply from %s of size %d\n", destination, recvSize);
ip_reply= (struct iphdr*) buffer;
printf("Reply's IP ID: %d and IP TTL: %d\n", ip_reply->id, ip_reply->ttl);
}
free(packet);
free(buffer);
close(pingSocket);
return 0;
}
unsigned short csum(unsigned short *ptr, int nbytes)
{
register long sum;
u_short oddbyte;
register u_short answer;
sum = 0;
while (nbytes > 1) {
sum += *ptr++;
nbytes -= 2;
}
if (nbytes == 1) {
oddbyte = 0;
*((u_char *) & oddbyte) = *(u_char *) ptr;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
char* getip()
{
char buffer[256];
struct hostent* h;
gethostname(buffer, 256);
h = gethostbyname(buffer);
return inet_ntoa(*(struct in_addr *)h->h_addr);
}
I read somewhere that someone fixed this issue by setting the ICMP checksum to Zero first and then calculating it. This however doesn't work for me. Please help me out :)

I/O redirection in a C program

I want to implement a simple "cat file1 > file1" command in a C program. I have tried the following, but it does not work...
main () {
pid_t pid;
FILE *ip, *op;
char *args[3];
printf("Name of the executable program\n\t");
scanf("%s", &name[0]); // I entered cat here
printf("Name of the input file\n\t");
scanf("%s", &name[1]); //file1.txt
printf("Name of the output file\n\t");
scanf("%s", &name[0]); //file2.txt
pid = fork();
if(pid == -1)
perror("fork() error");
else if(pid > 0)
waitpid(-1, NULL, 0);
else if (pid == 0) {
op = fopen(name[2], "w");
close(1);
dup(op);
execlp(name[0], name[1], NULL);
}
return 0;
}// end of main()
I thought the execlp() will run cat file1.txt and its output will be redirected to file2.txt, but it's not and I don't know why. How do I do it?
scanf("%s", &name[0]); // I entered cat here
printf("Name of the input file\n\t");
scanf("%s", &name[1]); //file1.txt
printf("Name of the output file\n\t");
scanf("%s", &name[0]); //file2.txt
Clearly not a C&P of actual code - name should be args, and the last one should be "2" instead of 0.
Also, dup works on file descriptors, not FILE*, so need to look at open rather than fopen, or whatever method gets the fd from a FILE*
The first argument to execlp() is the name to be looked up; the second and following arguments are the argv list, starting with argv[0].
int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);
For shell I/O redirection, it is easier to open files with open() than to use standard I/O (<stdio.h> and FILE *); you should also close the file you opened after the dup(), though it is easier to use dup2(). You need to allocate space to read the strings into; on many systems, the original code would crash because the pointers in str don't point anywhere. You should normally aim to exit with status 0 only if everything worked; otherwise, exit with a non-zero exit status.
This leads to:
#include <fcntl.h> /* open() */
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h> /* waitpid() */
#include <unistd.h> /* execlp(), fork(), dup2() */
int main(void)
{
pid_t pid;
pid_t corpse;
int status;
char name[3][50];
printf("Name of the executable program\n\t");
if (scanf("%49s", name[0]) != 1)
return(EXIT_FAILURE);
printf("Name of the input file\n\t");
if (scanf("%49s", name[1]) != 1)
return(EXIT_FAILURE);
printf("Name of the output file\n\t");
if (scanf("%49s", name[2]) != 1)
return(EXIT_FAILURE);
pid = fork();
if (pid == -1)
{
perror("fork() error");
return(EXIT_FAILURE);
}
else if (pid > 0)
corpse = waitpid(-1, &status, 0);
else
{
int fd = open(name[2], O_WRONLY|O_CREAT|O_EXCL, 0644);
if (fd < 0)
{
fprintf(stderr, "Failed to open %s for writing\n", name[2]);
return(EXIT_FAILURE);
}
dup2(fd, 1);
close(fd);
execlp(name[0], name[0], name[1], NULL);
fprintf(stderr, "Failed to exec %s\n", name[0]);
return(EXIT_FAILURE);
}
return(corpse == pid && status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
You have to either use fork() a process and reassign it's file descriptors to previously(manually) open()'ed file, or use system() call to make shell handle it for you.